From fe042c5a9f501da19451877aebd3cf004293bd40 Mon Sep 17 00:00:00 2001 From: Golubev Pavel Date: Thu, 7 Dec 2023 15:42:44 +0300 Subject: [PATCH 001/296] Initial commit --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..64cfaf6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 pachca + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 4195979823a3fa8797afb31bfb1e5d75cc309039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= Date: Thu, 12 Dec 2024 22:09:29 +0300 Subject: [PATCH 002/296] Initial commit --- .github/workflows/style_check.yml | 26 +++++ .gitignore | 165 ++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 17 +++ README.md | 29 ++++++ infra/.env.example | 1 + requirements_style.txt | 2 + ruff.toml | 43 ++++++++ src/main.py | 6 ++ src/requirements.txt | 1 + 9 files changed, 290 insertions(+) create mode 100644 .github/workflows/style_check.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 README.md create mode 100644 infra/.env.example create mode 100644 requirements_style.txt create mode 100644 ruff.toml create mode 100644 src/main.py create mode 100644 src/requirements.txt diff --git a/.github/workflows/style_check.yml b/.github/workflows/style_check.yml new file mode 100644 index 0000000..389c911 --- /dev/null +++ b/.github/workflows/style_check.yml @@ -0,0 +1,26 @@ +name: sytle_check + +on: + pull_request: + push: + branches: + - develop + - master + - main +jobs: + check_style: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set-up python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install dependies + run: | + python -m pip install --upgrade pip + pip install ruff==0.7.1 + + - name: Test style + run: python -m ruff check ./src diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9374355 --- /dev/null +++ b/.gitignore @@ -0,0 +1,165 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +.bot_venv +.backend_venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ +.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..7ea41c3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +repos: + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-merge-conflict + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.7.1 + hooks: + - id: ruff + args: [--fix, ./src] + - id: ruff-format diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ba8ab4 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Шаблон для проектов со стилизатором Ruff + +## Основное + +1. Базовая версия Python - 3.11. +2. В файле `requirements_style.txt` находятся зависимости для стилистики. +3. В каталоге `src` находится базовая структура проекта +4. В файле `srd/requirements.txt` прописываются базовые зависимости. +5. В каталоге `infra` находятся настроечные файлы проекта. Здесь же размещать файлы для docker compose. + +## Стилистика + +Для стилизации кода используется пакеты `Ruff` и `Pre-commit` + +Проверка стилистики кода осуществляется командой +```shell +ruff check +``` + +Если одновременно надо пофиксить то, что можно поиксить автоматически, то добавляем параметр `--fix` +```shell +ruff check --fix +``` + +Что бы стилистика автоматически проверялась и поправлялась при комитах надо добавить hook pre-commit к git + +```shell +pre-commit install +``` diff --git a/infra/.env.example b/infra/.env.example new file mode 100644 index 0000000..3c0d463 --- /dev/null +++ b/infra/.env.example @@ -0,0 +1 @@ +# Привер файла с переменными окружения diff --git a/requirements_style.txt b/requirements_style.txt new file mode 100644 index 0000000..92b963a --- /dev/null +++ b/requirements_style.txt @@ -0,0 +1,2 @@ +ruff==0.7.1 +pre-commit==3.8.0 diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..3a5ba86 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,43 @@ +indent-width = 4 +line-length = 79 +required-version = ">=0.6.1" +target-version = "py311" +# Enable preview features. +preview = true + +[format] +# Enable reformatting of code snippets in docstrings. +docstring-code-format = true +# Format all docstring code snippets with a line length of 60. +docstring-code-line-length = 60 +# Use `\n` line endings for all files +line-ending = "lf" +# Prefer single quotes over double quotes. +quote-style = "single" + +[lint] +ignore=["E265", "F811", "D100", "D105", "D104", "D203", "D211", "D213", "N818", "W505", "ANN401"] +select=["E3", "E5", "E4", "E7", "E9", "W", "C90", "I", "N", "D", "F", "ANN", "ASYNC", "A", "COM", "RET", ] + +[lint.extend-per-file-ignores] +# Also ignore in all files. +"__init__.py" = ["E402", "E401"] + +[lint.flake8-annotations] +allow-star-arg-any = true + +[lint.flake8-quotes] +inline-quotes = "single" + +[lint.isort] +case-sensitive = true +known-local-folder = ["src"] + +[lint.mccabe] +# Flag errors (`C901`) whenever the complexity level exceeds 5. +max-complexity = 10 + +[lint.pycodestyle] +max-doc-length = 79 +# E501 reports lines that exceed the length of 79. +max-line-length = 79 diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..7d16819 --- /dev/null +++ b/src/main.py @@ -0,0 +1,6 @@ +# Это основной запускаемый файл. +# Заменить содержимое своим кодом. + +import sys + +print(sys.path) diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..9815348 --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1 @@ +# Основные зависимости здесь From d8f93e16b76bb67d760107336ae5fb22c48c8e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= Date: Thu, 12 Dec 2024 22:09:51 +0300 Subject: [PATCH 003/296] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5ba8ab4..18161a5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ 2. В файле `requirements_style.txt` находятся зависимости для стилистики. 3. В каталоге `src` находится базовая структура проекта 4. В файле `srd/requirements.txt` прописываются базовые зависимости. -5. В каталоге `infra` находятся настроечные файлы проекта. Здесь же размещать файлы для docker compose. ## Стилистика From 8d7666388b31619b215280f185b758c6250207b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= Date: Thu, 12 Dec 2024 22:10:06 +0300 Subject: [PATCH 004/296] Delete infra directory --- infra/.env.example | 1 - 1 file changed, 1 deletion(-) delete mode 100644 infra/.env.example diff --git a/infra/.env.example b/infra/.env.example deleted file mode 100644 index 3c0d463..0000000 --- a/infra/.env.example +++ /dev/null @@ -1 +0,0 @@ -# Привер файла с переменными окружения From 43b0d004f7c69eb362350e40f9fa9a035430a9e4 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 13 Dec 2024 16:58:37 +0300 Subject: [PATCH 005/296] create a basic template for YAML contract --- openapi.yaml | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..33403a8 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,188 @@ +openapi: 3.0.3 +info: + title: PachcaAPI - OpenAPI 3.0 + description: Документация к открытому API пачки + version: 3.0.3 +servers: + - url: https://api.pachca.com/api/shared/v1 + +tags: + - name: common methods + description: Everything about common methods + - name: employees + description: Everything about employees + - name: status + description: Everything about + status + - name: tags + description: Everything about + tags + - name: chats and channels + description: Everything about + chats and channels + - name: talk and channel participants + description: Everything about + talk and channel participants + - name: comments + description: Everything about + comments + - name: messages + description: Everything about + messages + - name: reactions to messages + description: Everything about + reactions to messages + - name: reminders + description: Everything about + reminders + +paths: + /custom_properties: + get: + tags: + - common methods + summary: '43 / Список дополнительных полей' + description: 'Информация будет добавлена позже.' + /uploads: + post: + tags: + - common methods + summary: '44 / Получение подписи, ключа и других параметров' + description: 'Информация будет добавлена позже.' + /direct_url (полученный в ответе на запрос /uploads): + post: + tags: + - common methods + summary: '45 / Загрузка файла' + description: 'Информация будет добавлена позже.' + /users: + get: + tags: + - employees + summary: '4 / Список сотрудников' + description: 'Информация будет добавлена позже.' + /users/{id}: + get: + tags: + - employees + summary: '5 / Информация о сотруднике' + description: 'Информация будет добавлена позже.' + /profile/status: + get: + tags: + - status + summary: '8 / Текущий статус' + description: 'Информация будет добавлена позже.' + put: + tags: + - status + summary: '9 / Новый статус' + description: 'Информация будет добавлена позже.' + delete: + tags: + - status + summary: '10 / Удаление статуса' + description: 'Информация будет добавлена позже.' + /group_tags/{id}: + get: + tags: + - tags + summary: '12 / Информация о теге' + description: 'Информация будет добавлена позже.' + /group_tags: + get: + tags: + - tags + summary: '13 / Список тегов сотрудников' + description: 'Информация будет добавлена позже.' + /group_tags/{id}/users: + get: + tags: + - tags + summary: '14 / Список сотрудников тега' + description: 'Информация будет добавлена позже.' + /chats: + post: + tags: + - chats and channels + summary: '17 / Новая беседа или канал' + description: 'Информация будет добавлена позже.' + get: + tags: + - chats and channels + summary: '19 / Список бесед и каналов' + description: 'Информация будет добавлена позже.' + /chats/{id}: + get: + tags: + - chats and channels + summary: '18 / Информация о беседе или канале' + description: 'Информация будет добавлена позже.' + /chats/{id}/members: + post: + tags: + - talk and channel participants + summary: '23 / Добавление пользователей' + description: 'Информация будет добавлена позже.' + /chats/{id}/group_tags: + post: + tags: + - talk and channel participants + summary: '25 / Добавление тегов' + description: 'Информация будет добавлена позже.' + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + summary: '27 / Выход из беседы или канала' + description: 'Информация будет добавлена позже.' + /messages/{id}/thread: + delete: + tags: + - comments + summary: '28 / Новый тред' + description: 'Информация будет добавлена позже.' + /messages: + post: + tags: + - messages + summary: '30 / Новое сообщение' + description: 'Информация будет добавлена позже.' + get: + tags: + - messages + summary: '32 / Список сообщений чата' + description: 'Информация будет добавлена позже.' + /messages/{id}: + get: + tags: + - messages + summary: '31 / Информация о сообщении' + description: 'Информация будет добавлена позже.' + put: + tags: + - messages + summary: '33 / Редактирование сообщения' + description: 'Информация будет добавлена позже.' + /messages/{id}/reactions: + post: + tags: + - reactions to messages + summary: '38 / Добавление реакции' + description: 'Информация будет добавлена позже.' + delete: + tags: + - reactions to messages + summary: '39 / Удаление реакции' + description: 'Информация будет добавлена позже.' + get: + tags: + - reactions to messages + summary: '40 / Список реакций' + description: 'Информация будет добавлена позже.' + /tasks: + post: + tags: + - reminders + summary: '42 / Новое напоминание' + description: 'Информация будет добавлена позже.' From fb8af758242d9b12ae4e1b1308ec35677d42e2aa Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 13 Dec 2024 18:07:42 +0300 Subject: [PATCH 006/296] =?UTF-8?q?add=20path=204:=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=BE=D0=BA=20=D1=81=D0=BE=D1=82=D1=80=D1=83=D0=B4=D0=BD?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 134 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 33403a8..9e9e1eb 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -57,10 +57,136 @@ paths: description: 'Информация будет добавлена позже.' /users: get: - tags: - - employees - summary: '4 / Список сотрудников' - description: 'Информация будет добавлена позже.' + summary: получение актуального списка всех сотрудников компании + description: | + Fetch a paginated list of employees with optional filtering by query. + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + title: + type: string + description: Должность + role: + type: string + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + user_status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + bot: + type: boolean + description: Тип: пользователь (false) или бот (true) + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки /users/{id}: get: tags: From ccf70166d9c0bd0a6c67ca582b8afa97fca3b00b Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 13 Dec 2024 18:12:44 +0300 Subject: [PATCH 007/296] added tags for path --- openapi.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 9e9e1eb..bbb32a3 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -57,6 +57,8 @@ paths: description: 'Информация будет добавлена позже.' /users: get: + tags: + - employees summary: получение актуального списка всех сотрудников компании description: | Fetch a paginated list of employees with optional filtering by query. From a4940f3991579e5429a75a6d11bf18f27ce789d8 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 13 Dec 2024 18:22:51 +0300 Subject: [PATCH 008/296] added operationId --- openapi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/openapi.yaml b/openapi.yaml index bbb32a3..a8d1415 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -62,6 +62,7 @@ paths: summary: получение актуального списка всех сотрудников компании description: | Fetch a paginated list of employees with optional filtering by query. + operationId: getEmployees parameters: - name: per in: query From a7935e903c5473900401f90375878e3b1861cdbe Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 13 Dec 2024 18:45:23 +0300 Subject: [PATCH 009/296] add employee scema, use schema in path --- openapi.yaml | 191 ++++++++++++++++++++++++++------------------------- 1 file changed, 98 insertions(+), 93 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index a8d1415..d452f6a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -97,99 +97,7 @@ paths: data: type: array items: - type: object - properties: - id: - type: integer - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - title: - type: string - description: Должность - role: - type: string - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - user_status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - bot: - type: boolean - description: Тип: пользователь (false) или бот (true) - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки + $ref: '#/components/schemas/Employee' /users/{id}: get: tags: @@ -315,3 +223,100 @@ paths: - reminders summary: '42 / Новое напоминание' description: 'Информация будет добавлена позже.' + +components: + schemas: + Employee: + type: object + properties: + id: + type: integer + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + title: + type: string + description: Должность + role: + type: string + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + user_status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + bot: + type: boolean + description: Тип: пользователь (false) или бот (true) + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки \ No newline at end of file From 4bf6da4580a478fece29c8654e91c244fbcff48f Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 13 Dec 2024 19:42:52 +0300 Subject: [PATCH 010/296] add base employee schema --- openapi.yaml | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d452f6a..6bddfe2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -226,11 +226,12 @@ paths: components: schemas: - Employee: + BaseEmployee: type: object properties: id: type: integer + example: 1 description: Идентификатор пользователя first_name: type: string @@ -307,16 +308,24 @@ components: Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. bot: type: boolean - description: Тип: пользователь (false) или бот (true) - created_at: - type: string - format: date-time description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки \ No newline at end of file + Тип: пользователь (false) или бот (true) + description: Базовый класс сотрудника. + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. \ No newline at end of file From 380aca6d42785d1429412ebf48883347435ee74c Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 14 Dec 2024 10:15:53 +0300 Subject: [PATCH 011/296] add path: 5 info about employee, add not found error schema --- openapi.yaml | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6bddfe2..6783cec 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -102,8 +102,34 @@ paths: get: tags: - employees - summary: '5 / Информация о сотруднике' - description: 'Информация будет добавлена позже.' + summary: получение информации о сотруднике + description: | + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + operationId: getEmployee + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Employee' + '404': + description: Сотрудник не найден + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' /profile/status: get: tags: @@ -328,4 +354,12 @@ components: type: string nullable: true description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. \ No newline at end of file + description: Расширенный класс сотрудника. + NotFound: + description: Объект не найден + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Страница не найдена." + type: string \ No newline at end of file From fa7269a3ed299e4e793f2a6b4c2603bb79a53384 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 14 Dec 2024 13:28:24 +0300 Subject: [PATCH 012/296] add path: 14-get-tags-employees --- openapi.yaml | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6783cec..1522976 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -162,8 +162,51 @@ paths: get: tags: - tags - summary: '14 / Список сотрудников тега' - description: 'Информация будет добавлена позже.' + operationId: getTagsEmployees + summary: получение актуального списка сотрудников тега + description: | + Метод для получения актуального списка сотрудников тега. + operationId: getEmployees + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BaseEmployee' + '422': + description: Поле имеет недопустимое значение + content: + application/json: + schema: + $ref: '#/components/schemas/Exclusion' /chats: post: tags: @@ -362,4 +405,12 @@ components: detail: description: 'Описание ошибки' example: "Страница не найдена." + type: string + Exclusion: + description: Поле имеет недопустимое значение + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Поле имеет недопустимое значение." type: string \ No newline at end of file From 6870740e4522f1a0c6c6f2b99583155d57a8ba5b Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 14 Dec 2024 13:30:23 +0300 Subject: [PATCH 013/296] remove redundant operationId --- openapi.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 1522976..2915ee2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -166,7 +166,6 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. - operationId: getEmployees parameters: - name: id in: path From 68d2447e5fb0502f681a581b9460d76dea91ea39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sat, 14 Dec 2024 15:00:10 +0300 Subject: [PATCH 014/296] /profile/status: get --- openapi.yaml | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6783cec..bf4cf5a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -134,8 +134,22 @@ paths: get: tags: - status - summary: '8 / Текущий статус' - description: 'Информация будет добавлена позже.' + summary: получение информации о своем статусе + description: | + Параметры запроса отсутствуют + operationId: getStatus + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: object + items: + $ref: '#/components/schemas/Status' put: tags: - status @@ -355,6 +369,23 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. NotFound: description: Объект не найден type: object From 7b2b8e66adf05f4c129ec677b1352e70342fb039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sat, 14 Dec 2024 17:33:36 +0300 Subject: [PATCH 015/296] =?UTF-8?q?=D0=A7=D0=B0=D1=81=D1=82=D1=8C=209=20/?= =?UTF-8?q?=20=D0=9D=D0=BE=D0=B2=D1=8B=D0=B9=20=D1=81=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D1=83=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6783cec..3e7aa8e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -139,9 +139,44 @@ paths: put: tags: - status - summary: '9 / Новый статус' - description: 'Информация будет добавлена позже.' - delete: + summary: новый статус + description: | + Создание нового статуса. + operationId: putStatus + parameters: + status: + - name: emoji + in: status + description: Emoji символ статуса + schema: + type: string + required: true + - name: title + in: status + description: Текст статуса + schema: + type: string + required: true + - name: expires_at + in: status + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + schema: + type: string + format: date-time + nullable: true + required: false + responses: + '201': + description: Объект создан + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + delete: tags: - status summary: '10 / Удаление статуса' From ab9083c309be0ca292e7fd715deecebfa4a0efae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sat, 14 Dec 2024 18:14:51 +0300 Subject: [PATCH 016/296] Status_codes --- openapi.yaml | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6db9678..d712cc4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -190,7 +190,36 @@ paths: properties: data: $ref: '#/components/schemas/Status' - delete: + '400': + description: Обязательное поле (не может быть пустым) + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + '413': + description: Слишком длинное значение (пояснения вы получите в поле message) + content: + application/json: + schema: + $ref: '#/components/schemas/ContentTooLarge' + '422': + description: Поле не соответствует правилам (пояснения вы получите в поле message) + content: + application/json: + schema: + $ref: '#/components/schemas/UnprocessableContent' + '400': + description: Status wrong Emoji + content: + application/json: + schema: + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Emoji статуса не может содержать значения отличные от Emoji символа." + type: string + delete: tags: - status summary: '10 / Удаление статуса' @@ -428,4 +457,28 @@ components: detail: description: 'Описание ошибки' example: "Страница не найдена." - type: string \ No newline at end of file + type: string + BadRequest: + description: Отсутствует обязательное поле + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Обязательное поле (не может быть пустым)." + type: string + ContentTooLarge: + description: Слишком длинное значение + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Слишком длинное значение (пояснения вы получите в поле message)" + type: string + UnprocessableContent: + description: Поле не соответствует правилам + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Поле не соответствует правилам (пояснения вы получите в поле message)" + type: string From 379ca19a155f1a500fe6db2a0cb093bd527ede9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sat, 14 Dec 2024 21:21:06 +0300 Subject: [PATCH 017/296] delete status --- openapi.yaml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d712cc4..96694af 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -222,8 +222,20 @@ paths: delete: tags: - status - summary: '10 / Удаление статуса' - description: 'Информация будет добавлена позже.' + summary: удаление своего статуса + description: | + Параметры запроса отсутствуют + operationId: delStatus + responses: + '204': + description: Объект успешно удален + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/NoContent' /group_tags/{id}: get: tags: @@ -482,3 +494,11 @@ components: description: 'Описание ошибки' example: "Поле не соответствует правилам (пояснения вы получите в поле message)" type: string + NoContent: + description: Успешное удаление объекта + type: object + properties: + detail: + description: 'Объект удален' + example: "Объект удален" + type: string From a0c9010e34a26593796048b723223300206682d8 Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sat, 14 Dec 2024 23:31:03 +0300 Subject: [PATCH 018/296] fixed the schematic display --- openapi.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index bf4cf5a..a7a59d9 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -147,9 +147,7 @@ paths: type: object properties: data: - type: object - items: - $ref: '#/components/schemas/Status' + $ref: '#/components/schemas/Status' put: tags: - status @@ -393,4 +391,4 @@ components: detail: description: 'Описание ошибки' example: "Страница не найдена." - type: string \ No newline at end of file + type: string From b3cf52c96725b7c4e0ac6e3c0af5c2d0a2db8a96 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 15 Dec 2024 10:45:29 +0300 Subject: [PATCH 019/296] fix schema to match documentation --- openapi.yaml | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 2915ee2..e43d58a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -309,19 +309,16 @@ components: description: Фамилия nickname: type: string - description: Имя пользователя + description: Имя пользователя email: type: string - description: Электронная почта + description: Электронная почта phone_number: type: string description: Телефон department: type: string - description: Департамент - title: - type: string - description: Должность + description: Департамент role: type: string description: | @@ -341,7 +338,7 @@ components: description: Массив тегов, привязанных к сотруднику custom_properties: type: array - description: Дополнительные поля сотрудника + description: Дополнительные поля сотрудника items: type: object properties: @@ -357,23 +354,6 @@ components: value: type: string description: Значение - user_status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. bot: type: boolean description: | @@ -384,6 +364,26 @@ components: - $ref: '#/components/schemas/BaseEmployee' - type: object properties: + user_status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + title: + type: string + description: Должность created_at: type: string format: date-time @@ -396,7 +396,7 @@ components: type: string nullable: true description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. + description: Расширенный класс сотрудника. NotFound: description: Объект не найден type: object @@ -406,10 +406,10 @@ components: example: "Страница не найдена." type: string Exclusion: - description: Поле имеет недопустимое значение + description: Поле имеет недопустимое значение type: object properties: detail: description: 'Описание ошибки' - example: "Поле имеет недопустимое значение." + example: 'Поле имеет недопустимое значение.' type: string \ No newline at end of file From 104ddfb596b17df757615cc3680c6061f1459182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 13:17:31 +0300 Subject: [PATCH 020/296] the scheme for the request --- openapi.yaml | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index f6d5360..329cefb 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -156,28 +156,7 @@ paths: Создание нового статуса. operationId: putStatus parameters: - status: - - name: emoji - in: status - description: Emoji символ статуса - schema: - type: string - required: true - - name: title - in: status - description: Текст статуса - schema: - type: string - required: true - - name: expires_at - in: status - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - schema: - type: string - format: date-time - nullable: true - required: false + $ref: '#/components/schemas/QueryStatus' responses: '201': description: Объект создан @@ -446,6 +425,29 @@ components: nullable: true description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + status: + - name: emoji + in: status + description: Emoji символ статуса + schema: + type: string + required: true + - name: title + in: status + description: Текст статуса + schema: + type: string + required: true + - name: expires_at + in: status + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + schema: + type: string + format: date-time + nullable: true + required: false NotFound: description: Объект не найден type: object From 5ed99b3f0df1decd3ae4430335dcd0869f042a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 13:56:48 +0300 Subject: [PATCH 021/296] fixed --- openapi.yaml | 73 +++++++++++++++++----------------------------------- 1 file changed, 24 insertions(+), 49 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 96694af..43aec61 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -147,9 +147,7 @@ paths: type: object properties: data: - type: object - items: - $ref: '#/components/schemas/Status' + $ref: '#/components/schemas/Status' put: tags: - status @@ -158,28 +156,7 @@ paths: Создание нового статуса. operationId: putStatus parameters: - status: - - name: emoji - in: status - description: Emoji символ статуса - schema: - type: string - required: true - - name: title - in: status - description: Текст статуса - schema: - type: string - required: true - - name: expires_at - in: status - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - schema: - type: string - format: date-time - nullable: true - required: false + $ref: '#/components/schemas/QueryStatus' responses: '201': description: Объект создан @@ -191,34 +168,32 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: Обязательное поле (не может быть пустым) + description: BadRequest content: application/json: schema: $ref: '#/components/schemas/BadRequest' - '413': - description: Слишком длинное значение (пояснения вы получите в поле message) - content: - application/json: - schema: - $ref: '#/components/schemas/ContentTooLarge' - '422': - description: Поле не соответствует правилам (пояснения вы получите в поле message) - content: - application/json: - schema: - $ref: '#/components/schemas/UnprocessableContent' - '400': - description: Status wrong Emoji - content: - application/json: - schema: - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Emoji статуса не может содержать значения отличные от Emoji символа." - type: string + examples: + BLANK: + summary: blank + description: Обязательное поле (не может быть пустым) + value: + detail: BLANK + TOO_LONG: + summary: too_long + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + detail: TOO_LONG + INVALID: + summary: invalid + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + detail: INVALID + WRONG_EMOJI: + summary: wrong_emoji + description: Emoji статуса не может содержать значения отличные от Emoji символа + value: + detail: WRONG_EMOJI delete: tags: - status From e1870e85b694cf3a8c466d5549fbe8ebfce54534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 14:04:41 +0300 Subject: [PATCH 022/296] fixed responses delete --- openapi.yaml | 68 ++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 43aec61..82968de 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -203,14 +203,8 @@ paths: operationId: delStatus responses: '204': - description: Объект успешно удален - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/NoContent' + description: Объект успешно удален, тело ответа отсутствует + content: {} /group_tags/{id}: get: tags: @@ -437,6 +431,29 @@ components: nullable: true description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + status: + - name: emoji + in: status + description: Emoji символ статуса + schema: + type: string + required: true + - name: title + in: status + description: Текст статуса + schema: + type: string + required: true + - name: expires_at + in: status + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + schema: + type: string + format: date-time + nullable: true + required: false NotFound: description: Объект не найден type: object @@ -446,34 +463,7 @@ components: example: "Страница не найдена." type: string BadRequest: - description: Отсутствует обязательное поле - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Обязательное поле (не может быть пустым)." - type: string - ContentTooLarge: - description: Слишком длинное значение - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Слишком длинное значение (пояснения вы получите в поле message)" - type: string - UnprocessableContent: - description: Поле не соответствует правилам - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Поле не соответствует правилам (пояснения вы получите в поле message)" - type: string - NoContent: - description: Успешное удаление объекта - type: object - properties: - detail: - description: 'Объект удален' - example: "Объект удален" - type: string + summary: BadRequest + description: Bad Request + value: + detail: BadRequest From 4846a0ab8dd8d25b11a4c568bd9788c6a0a7a548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 20:27:31 +0300 Subject: [PATCH 023/296] fixed QueryStatus, BadRequest --- openapi.yaml | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index b383514..db9944a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -459,28 +459,26 @@ components: description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. QueryStatus: + type: object + properties: status: - - name: emoji - in: status - description: Emoji символ статуса - schema: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: type: string - required: true - - name: title - in: status - description: Текст статуса - schema: + description: Emoji символ статуса + title: type: string - required: true - - name: expires_at - in: status - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - schema: + description: Текст статуса + expires_at: type: string format: date-time + description: Срок жизни статуса (ISO-8601, UTC+0) nullable: true - required: false NotFound: description: Объект не найден type: object @@ -490,7 +488,9 @@ components: example: "Страница не найдена." type: string BadRequest: - summary: BadRequest - description: Bad Request - value: - detail: BadRequest \ No newline at end of file + type: object + properties: + error: + type: string + message: + type: string \ No newline at end of file From 2768bd9dcf96a86d100c412936176039cf325f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 20:37:05 +0300 Subject: [PATCH 024/296] fixed method put status --- openapi.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index db9944a..27f44de 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -155,8 +155,12 @@ paths: description: | Создание нового статуса. operationId: putStatus - parameters: - $ref: '#/components/schemas/QueryStatus' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' responses: '201': description: Объект создан From c6ab3def2d7d966f675c1212bba579efaddeca1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 20:41:36 +0300 Subject: [PATCH 025/296] fixed description expires_at --- openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 27f44de..6b64c7d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -481,7 +481,7 @@ components: expires_at: type: string format: date-time - description: Срок жизни статуса (ISO-8601, UTC+0) + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ nullable: true NotFound: description: Объект не найден From e8b06f3ebc8ddff36dd6fb3684f195ea6f9a14c4 Mon Sep 17 00:00:00 2001 From: Alexander-Klp Date: Sun, 15 Dec 2024 21:31:48 +0300 Subject: [PATCH 026/296] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=80=D1=83=D1=87=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D1=80=D0=B5=D0=B0=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6783cec..bd97dcb 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -241,8 +241,52 @@ paths: get: tags: - reactions to messages - summary: '40 / Список реакций' - description: 'Информация будет добавлена позже.' + summary: 'Получение актуального списка реакций.' + description: | + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. + operationId: getMessageReactions + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. + schema: + type: integer + - name: per + in: query + required: false + description: Количество возвращаемых сущностей за запрос (по умолчанию 50, максимум 50). + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + required: false + description: Номер страницы результатов (по умолчанию 1). + schema: + type: integer + default: 1 + responses: + '200': + description: Список реакций успешно получен. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Reaction' + '404': + description: Сообщение не найдено. + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + '400': + description: Неверный запрос. /tasks: post: tags: From 02bfa35b4bde1df43f46c385c0b7814c9fcfa841 Mon Sep 17 00:00:00 2001 From: Alexander-Klp Date: Sun, 15 Dec 2024 21:44:40 +0300 Subject: [PATCH 027/296] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=81=D1=85=D0=B5=D0=BC=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BA=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index bd97dcb..e25086a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -406,4 +406,20 @@ components: detail: description: 'Описание ошибки' example: "Страница не найдена." - type: string \ No newline at end of file + type: string + Reaction: + type: object + properties: + user_id: + type: integer + description: | + Идентификатор пользователя, оставившего реакцию. + created_at: + type: string + format: date-time + description: | + Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + code: + type: string + description: | + Emoji символ реакции. \ No newline at end of file From cece9858f4cdb4b58682a20c82e15eaf6368be01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 22:35:23 +0300 Subject: [PATCH 028/296] fix --- openapi.yaml | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6b64c7d..b383514 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -155,12 +155,8 @@ paths: description: | Создание нового статуса. operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/QueryStatus' + parameters: + $ref: '#/components/schemas/QueryStatus' responses: '201': description: Объект создан @@ -463,26 +459,28 @@ components: description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. QueryStatus: - type: object - properties: status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title - properties: - emoji: + - name: emoji + in: status + description: Emoji символ статуса + schema: type: string - description: Emoji символ статуса - title: + required: true + - name: title + in: status + description: Текст статуса + schema: type: string - description: Текст статуса - expires_at: + required: true + - name: expires_at + in: status + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + schema: type: string format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ nullable: true + required: false NotFound: description: Объект не найден type: object @@ -492,9 +490,7 @@ components: example: "Страница не найдена." type: string BadRequest: - type: object - properties: - error: - type: string - message: - type: string \ No newline at end of file + summary: BadRequest + description: Bad Request + value: + detail: BadRequest \ No newline at end of file From 89d641030ffe2dd9cdae79fb4ccec06ff939c356 Mon Sep 17 00:00:00 2001 From: Alexander-Klp Date: Sun, 15 Dec 2024 22:43:24 +0300 Subject: [PATCH 029/296] =?UTF-8?q?=D0=9A=D0=BE=D0=BB=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=BE=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0?= =?UTF-8?q?=D1=89=D0=B0=D0=B5=D0=BC=D1=8B=D1=85=20=D1=81=D1=83=D1=89=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B5=D0=B9=20=D0=B8=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=B2=20=D1=82=D0=B5=D0=BB=D0=BE=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index e25086a..5e6e28e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -252,21 +252,22 @@ paths: description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за запрос (по умолчанию 50, максимум 50). - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - required: false - description: Номер страницы результатов (по умолчанию 1). - schema: - type: integer - default: 1 + requestBody: + required: false + content: + application/json: + schema: + type: object + properties: + per: + type: integer + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). + default: 50 + maximum: 50 + page: + type: integer + description: Номер страницы выборки (по умолчанию 1). + default: 1 responses: '200': description: Список реакций успешно получен. From d7d8fa6ea2504d80fa42e23416b0a56c61d97a33 Mon Sep 17 00:00:00 2001 From: Alexander-Klp Date: Sun, 15 Dec 2024 22:49:20 +0300 Subject: [PATCH 030/296] =?UTF-8?q?400=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=81=D1=81=D1=8B=D0=BB=D0=B0=D1=8E=D1=81=D1=8C=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=83=D0=B6=D0=B5=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=83=D1=8E=20=D1=81=D1=85=D0=B5=D0=BC=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index b0b95a6..ccb54be 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -393,6 +393,10 @@ paths: $ref: '#/components/schemas/NotFound' '400': description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' /tasks: post: tags: From f1ba77f0a0a331565973e3264886fc42bedd0ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 22:55:29 +0300 Subject: [PATCH 031/296] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=81=D1=85=D0=B5=D0=BC=D1=8B=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=20=D0=BE?= =?UTF-8?q?=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C=20=D0=B4=D0=BE=D0=BA?= =?UTF-8?q?=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлены схемы CreateMessage и Message для работы с сообщениями. - Добавлены схемы ошибок ErrorModel и NotFound. - Реализован эндпоинт POST /messages с примерами ошибок 400 и 404 в OpenAPI. --- openapi.yaml | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 6783cec..da51664 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -211,6 +211,42 @@ paths: - messages summary: '30 / Новое сообщение' description: 'Информация будет добавлена позже.' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateMessage' + responses: + '200': + description: 'Сообщение отправлено' + content: + application/json: + schema: + $ref: '#/components/schemas/Message' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + detail: "Беседа с таким id не найдена" + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorModel' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + detail: Поле не может быть пустым + INVALID FIELD VALUE: + summary: invalid field value + value: + detail: Поле имеет недопустимое значение get: tags: - messages @@ -362,4 +398,202 @@ components: detail: description: 'Описание ошибки' example: "Страница не найдена." - type: string \ No newline at end of file + type: string + ErrorModel: + title: ErrorModel + required: + - detail + type: object + properties: + detail: + title: Detail + anyOf: + - type: string + - type: object + additionalProperties: + type: string + BaseMessage: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + parent_massage_id: + title: Parent Massage Id + type: integer + CreateMessage: + type: object + allOf: + - $ref: '#/components/schemas/BaseMessage' + required: + - entity_id + - content + properties: + files: + title: Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + name: + title: Name + type: string + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + size: + title: Size + type: integer + buttons: + title: Buttons + type: array + maxItems: 100 + items: + title: Button + type: array + maxItems: 8 + items: + type: object + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + link_preview: + title: Link Preview + type: boolean + default: false + Message: + type: object + allOf: + - $ref: '#/components/schemas/BaseMessage' + properties: + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + name: + title: Name + type: string + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + buttons: + title: Buttons + type: array + items: + title: Button + type: array + items: + type: object + properties: + text: + title: Text + type: string + url: + title: Url + type: string + data: + title: Data + type: string + thread: + title: Thread + type: object + nullable: true + properties: + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + forwarding: + title: Forwarding + type: object + nullable: true + properties: + original_message_id: + title: Origin Message Id + type: integer + original_chat_id: + title: Original Chat Id + type: integer + author_id: + title: Author Id + type: integer + original_created_at: + title: Original Created At + type: integer + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true \ No newline at end of file From ca427cbcbb1351067457f879a5171f7d0d9208a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 15 Dec 2024 23:41:13 +0300 Subject: [PATCH 032/296] =?UTF-8?q?=D0=A1=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D1=85=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9=20com?= =?UTF-8?q?mon=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 106 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 24 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index b383514..00a3c38 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -41,8 +41,46 @@ paths: get: tags: - common methods - summary: '43 / Список дополнительных полей' - description: 'Информация будет добавлена позже.' + summary: Список дополнительных полей + description: | + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + operationId: getCommonMethods + parameters: + - name: entity_type + in: query + description: Тип сущности - участник (User) или напоминание (Task). + required: true + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/QueryCommonMethods' + '400': + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + BLANK: + summary: blank + description: Поле не может быть пустым + value: + detail: BLANK + INCLUSION: + summary: inclusion + description: Поле имеет непредусмотренное значение + value: + detail: INCLUSION /uploads: post: tags: @@ -155,8 +193,12 @@ paths: description: | Создание нового статуса. operationId: putStatus - parameters: - $ref: '#/components/schemas/QueryStatus' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' responses: '201': description: Объект создан @@ -459,28 +501,42 @@ components: description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. QueryStatus: + type: object + properties: status: - - name: emoji - in: status - description: Emoji символ статуса - schema: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: type: string - required: true - - name: title - in: status - description: Текст статуса - schema: + description: Emoji символ статуса + title: type: string - required: true - - name: expires_at - in: status - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - schema: + description: Текст статуса + expires_at: type: string format: date-time + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ nullable: true - required: false + QueryCommonMethods: + type: object + description: получение списка актульных полей сущности. + properties: + id: + type: integer + example: 1 + description: Название поля + name: + type: string + example: Дата рождения + description: Идентификатор поля + data_type: + type: string + example: number + description: тип поля (string, number, date или link) NotFound: description: Объект не найден type: object @@ -490,7 +546,9 @@ components: example: "Страница не найдена." type: string BadRequest: - summary: BadRequest - description: Bad Request - value: - detail: BadRequest \ No newline at end of file + type: object + properties: + error: + type: string + message: + type: string From acea02abda9df3d5b38f52f0024b256591bd2a13 Mon Sep 17 00:00:00 2001 From: Alexander-Klp Date: Mon, 16 Dec 2024 13:00:27 +0300 Subject: [PATCH 033/296] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=80=D1=83=D1=87=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE=20=D1=82=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 55 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index ccb54be..d447da1 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -305,11 +305,60 @@ paths: summary: '27 / Выход из беседы или канала' description: 'Информация будет добавлена позже.' /messages/{id}/thread: - delete: + post: tags: - comments - summary: '28 / Новый тред' - description: 'Информация будет добавлена позже.' + summary: Создание нового треда + description: | + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '200': + description: Тред успешно создан или возвращены данные существующего треда. + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного треда. + chat_id: + type: integer + description: Идентификатор чата треда. + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + '404': + description: Сообщение не найдено. + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + '400': + description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' /messages: post: tags: From c86f1706b100544e27f0e0ded52ff5dcf88db070 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Mon, 16 Dec 2024 23:41:53 +0500 Subject: [PATCH 034/296] 27-Exiting-a-conversation-or-channel --- openapi.yaml | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 49a6452..5287835 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -341,7 +341,42 @@ paths: tags: - talk and channel participants summary: '27 / Выход из беседы или канала' - description: 'Информация будет добавлена позже.' + description: |- + Удаляет себя из беседы или канала. Доступно только авторизованным. + security: + - Token: [ ] + parameters: + - name: id + in: path + required: true + description: 'Уникальный идентификатор беседы или канала.' + schema: + type: integer + responses: + '200': + description: 'Успешно отписан' + content: + application/json: + schema: + $ref: '#/components/schemas/BaseEmployee' + '400': + description: 'Ошибка удаления из беседы или канала (Например, не подписан на данную беседу или канал)' + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + '401': + description: Пользователь не авторизован' + content: + application/json: + schema: + $ref: '#/components/schemas/AuthenticationError' + '404': + description: 'Беседа или канал не существует' + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' /messages/{id}/thread: delete: tags: @@ -617,3 +652,16 @@ components: type: string message: type: string + AuthenticationError: + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Учетные данные не были предоставлены." + type: string + securitySchemes: + Token: + description: 'Авторизация по токену.
+ Все запросы от имени пользователя должны выполняться с заголовком "Authorization: Token TOKENVALUE"' + type: http + scheme: token From 1972bfddb0db8bb2b16e565d2d10e4a22f911215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 16 Dec 2024 21:43:15 +0300 Subject: [PATCH 035/296] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=80=D1=83=D1=87=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5?= =?UTF-8?q?=D0=B0=D0=BA=D1=86=D0=B8=D0=B9=20=D0=BA=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index ccb54be..66c536c 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -336,8 +336,99 @@ paths: post: tags: - reactions to messages - summary: '38 / Добавление реакции' - description: 'Информация будет добавлена позже.' + operationId: postMessageReactions + summary: Добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + description: Emoji в строковом формате для добавления реакции. + required: + - code + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + blank_field: + summary: Поле code пустое + value: + error: blank + exclusion: + summary: Недопустимое значение эмодзи + value: + error: exclusion + + "403": + description: Превышение лимитов по реакциям. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + user_limit: + summary: Превышен лимит уникальных реакций пользователя + value: + error: user_limit + message: "Вы можете добавить не более 20 уникальных реакций." + unique_limit: + summary: Превышен лимит уникальных реакций на сообщение + value: + error: unique_limit + message: "Сообщение может содержать не более 30 уникальных реакций." + general_limit: + summary: Превышен общий лимит реакций на сообщение + value: + error: general_limit + message: "Сообщение может содержать не более 1000 реакций." + + "404": + description: Сообщение не найдено. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Сообщение не найдено. + examples: + not_found: + summary: Сообщение не существует + value: + error: not_found delete: tags: - reactions to messages From 1024b75dcbe67470d083f4a6394caf336ecd6468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Mon, 16 Dec 2024 23:38:43 +0300 Subject: [PATCH 036/296] Tag-information --- openapi.yaml | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 49a6452..98a2828 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -251,8 +251,26 @@ paths: get: tags: - tags - summary: '12 / Информация о теге' - description: 'Информация будет добавлена позже.' + summary: Информация о теге + description: | + Параметры запроса отсутствуют + operationId: getTag + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + '404': + description: Тег не найден + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' /group_tags: get: tags: @@ -617,3 +635,16 @@ components: type: string message: type: string + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer \ No newline at end of file From 135982a0d8ce9997c4c5683cf5c94454464ce8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Tue, 17 Dec 2024 01:03:56 +0300 Subject: [PATCH 037/296] Add parameters --- openapi.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 98a2828..2772be8 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -255,6 +255,13 @@ paths: description: | Параметры запроса отсутствуют operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer responses: '200': description: Успешный запрос From 01044408bf4cd8c0427521d6246baa1296b6924e Mon Sep 17 00:00:00 2001 From: Pavel Kolesnikov Date: Tue, 17 Dec 2024 01:47:56 +0300 Subject: [PATCH 038/296] add new reminder --- openapi.yaml | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 49a6452..ecb0135 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -441,6 +441,118 @@ paths: - reminders summary: '42 / Новое напоминание' description: 'Информация будет добавлена позже.' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + kind: + type: string + description: Тип + content: + type: string + description: Описание + due_at: + type: string + format: date-time + description: Срок выполнения (ISO-8601) + priority: + type: integer + description: Приоритет + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + performer_ids: + type: array + items: + type: integer + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + + '400': + description: Ошибка запроса + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки components: schemas: From e2817aa7c8ccbc01ba02e6ff0906750974aca7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D0=BE=D1=80=D0=B0?= Date: Tue, 17 Dec 2024 01:51:10 +0300 Subject: [PATCH 039/296] feature 25 add tags 01:51 --- openapi.yaml | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 49a6452..2031941 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -333,9 +333,47 @@ paths: /chats/{id}/group_tags: post: tags: - - talk and channel participants - summary: '25 / Добавление тегов' - description: 'Информация будет добавлена позже.' + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + responses: + '201': + description: Тег(и) добавлен(ы) + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' /chats/{id}/leave: delete: tags: @@ -617,3 +655,17 @@ components: type: string message: type: string + ErrorsCode: + description: Bad Request + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object \ No newline at end of file From 17f7490f67bc5c29dafb3ab858e06136c0e397fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D0=BE=D1=80=D0=B0?= Date: Tue, 17 Dec 2024 01:55:05 +0300 Subject: [PATCH 040/296] feature 25 add tags 01:55 --- openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 2031941..216565e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -668,4 +668,4 @@ components: code: type: string payload: - type: object \ No newline at end of file + type: object From cd4357e28073cd9d9035707c2072ac216dd72c0a Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 09:12:26 +0500 Subject: [PATCH 041/296] =?UTF-8?q?#18=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=87=D0=B0=D1=82=D0=B0=20=D0=B8=D0=BB=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=B0=D0=BD=D0=B0=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 49a6452..5e8ffdc 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -322,8 +322,34 @@ paths: get: tags: - chats and channels - summary: '18 / Информация о беседе или канале' - description: 'Информация будет добавлена позже.' + operationId: getChatInfo + summary: Информация о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '404': + description: Не удалось найти + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' /chats/{id}/members: post: tags: @@ -617,3 +643,56 @@ components: type: string message: type: string + Chat: + type: object + description: Беседа или канал + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + name: + type: string + description: Название + example: 🤿 aqua + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + member_ids: + type: array + description: Массив идентификаторов пользователей, участников + items: + type: integer + example: + - 185 + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (false) или открытый (true)' + example: false + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' From 54456f49ca853f4daa6e96b24c00ea7eec7aee68 Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:40:30 +0300 Subject: [PATCH 042/296] add title and description in post /tasks --- openapi.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index ecb0135..d6ca39e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -439,8 +439,12 @@ paths: post: tags: - reminders - summary: '42 / Новое напоминание' - description: 'Информация будет добавлена позже.' + summary: 'Метод для создания нового напоминания.' + description: | + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. requestBody: required: true content: From 6c69884b4063916df48ab7676b52df7536e09564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 16:10:21 +0300 Subject: [PATCH 043/296] =?UTF-8?q?-=20=D0=9F=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B0=D0=BD=D1=8B=20=D1=81=D1=85=D0=B5=D0=BC=D1=8B?= =?UTF-8?q?=20CreateMessage,=20Message=20-=20=D0=98=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B8=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 133 +++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index da51664..05ccef2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -209,8 +209,22 @@ paths: post: tags: - messages - summary: '30 / Новое сообщение' - description: 'Информация будет добавлена позже.' + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage requestBody: required: true content: @@ -218,8 +232,7 @@ paths: schema: $ref: '#/components/schemas/CreateMessage' responses: - '200': - description: 'Сообщение отправлено' + '201': content: application/json: schema: @@ -231,7 +244,7 @@ paths: schema: $ref: '#/components/schemas/NotFound' example: - detail: "Беседа с таким id не найдена" + detail: "Не удалось найти" '400': description: Bad Request content: @@ -412,8 +425,11 @@ components: - type: object additionalProperties: type: string - BaseMessage: + CreateMessage: type: object + required: + - entity_id + - content properties: entity_type: title: Entity Type @@ -429,17 +445,6 @@ components: content: title: Content type: string - parent_massage_id: - title: Parent Massage Id - type: integer - CreateMessage: - type: object - allOf: - - $ref: '#/components/schemas/BaseMessage' - required: - - entity_id - - content - properties: files: title: Files type: array @@ -466,43 +471,41 @@ components: size: title: Size type: integer - buttons: - title: Buttons - type: array - maxItems: 100 - items: - title: Button - type: array - maxItems: 8 - items: - type: object - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null skip_invite_mentions: title: Skip Invite Mentions type: boolean + default: false link_preview: title: Link Preview type: boolean default: false + example: + message: + entity_type: discussion + entity_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) Message: type: object - allOf: - - $ref: '#/components/schemas/BaseMessage' properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string id: title: Id type: integer @@ -515,6 +518,7 @@ components: created_at: title: Created At type: string + format: date-time files: title: Files type: array @@ -539,28 +543,11 @@ components: url: title: Url type: string - buttons: - title: Buttons - type: array - items: - title: Button - type: array - items: - type: object - properties: - text: - title: Text - type: string - url: - title: Url - type: string - data: - title: Data - type: string thread: title: Thread type: object nullable: true + default: null properties: id: title: Id @@ -572,6 +559,7 @@ components: title: Forwarding type: object nullable: true + default: null properties: original_message_id: title: Origin Message Id @@ -596,4 +584,23 @@ components: original_thread_parent_chat_id: title: Original Thread Parent Chat Id type: integer - nullable: true \ No newline at end of file + nullable: true + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + example: + data: + id: 194275, + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null \ No newline at end of file From 93115d9405dc5112ec7fba03de1bfa3b76068065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 16:27:57 +0300 Subject: [PATCH 044/296] =?UTF-8?q?-=20=D0=9F=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B0=D0=BD=D1=8B=20=D1=81=D1=85=D0=B5=D0=BC=D1=8B?= =?UTF-8?q?=20CreateMessage,=20Message=20-=20=D0=98=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B8=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 857934d..27a2e72 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -762,6 +762,20 @@ components: title: Original Thread Parent Chat Id type: integer nullable: true + example: + data: + id: 194275, + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null Reaction: type: object properties: @@ -789,18 +803,4 @@ components: title: Parent Massage Id type: integer nullable: true - default: null - example: - data: - id: 194275, - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null \ No newline at end of file + default: null \ No newline at end of file From 8b1ae6653fb040be3cb925999d2e8ada20cba0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 16:44:19 +0300 Subject: [PATCH 045/296] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=B5=D0=BD=D0=BE=20=D0=BF=D0=BE=D0=BB=D0=B5=20parent=5F?= =?UTF-8?q?message=5Fid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 27a2e72..4b3918c 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -762,6 +762,11 @@ components: title: Original Thread Parent Chat Id type: integer nullable: true + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null example: data: id: 194275, @@ -798,9 +803,4 @@ components: error: type: string message: - type: string - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null \ No newline at end of file + type: string \ No newline at end of file From be4e199fbe6c0f3b98ed8b3e4fb1882243885c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 17:32:22 +0300 Subject: [PATCH 046/296] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20requestBody=20=D0=B8=20response=20=D0=B2?= =?UTF-8?q?=20paths:=20/message:=20post?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 4b3918c..d0f2398 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -335,13 +335,19 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CreateMessage' + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' responses: '201': content: application/json: schema: - $ref: '#/components/schemas/Message' + type: object + properties: + data: + $ref: '#/components/schemas/Message' '404': description: Not Found content: @@ -662,10 +668,9 @@ components: type: boolean default: false example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + entity_type: discussion + entity_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) Message: type: object properties: @@ -768,19 +773,18 @@ components: nullable: true default: null example: - data: - id: 194275, - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null + id: 194275, + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null Reaction: type: object properties: From 75530ba14922c4e1a176b567e0b6de1d7692e05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 17:55:50 +0300 Subject: [PATCH 047/296] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BA=D1=86=D0=B8=D0=B9=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d6708ce..17c843e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -608,8 +608,63 @@ paths: delete: tags: - reactions to messages - summary: '39 / Удаление реакции' - description: 'Информация будет добавлена позже.' + operationId: deleteMessageReactions + summary: Удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: string + - name: code + in: query + required: true + description: Emoji, который нужно удалить. + schema: + type: string + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + blank_field: + summary: Поле code пустое + value: + error: blank + exclusion: + summary: Недопустимое значение эмодзи + value: + error: exclusion + + "404": + description: Сообщение или реакция не найдены. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + not_found: + summary: Сообщение или реакция не найдены + value: + error: not_found get: tags: - reactions to messages From 3473625052788e8c5c1e9f6e7f1f9a4243d5cea2 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 17 Dec 2024 20:13:22 +0500 Subject: [PATCH 048/296] 27_2 --- openapi.yaml | 476 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 444 insertions(+), 32 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 5287835..63465a7 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -251,8 +251,33 @@ paths: get: tags: - tags - summary: '12 / Информация о теге' - description: 'Информация будет добавлена позже.' + summary: Информация о теге + description: | + Параметры запроса отсутствуют + operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + '404': + description: Тег не найден + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' /group_tags: get: tags: @@ -322,8 +347,34 @@ paths: get: tags: - chats and channels - summary: '18 / Информация о беседе или канале' - description: 'Информация будет добавлена позже.' + operationId: getChatInfo + summary: Информация о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '404': + description: Не удалось найти + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' /chats/{id}/members: post: tags: @@ -333,16 +384,54 @@ paths: /chats/{id}/group_tags: post: tags: - - talk and channel participants - summary: '25 / Добавление тегов' - description: 'Информация будет добавлена позже.' + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + responses: + '201': + description: Тег(и) добавлен(ы) + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' /chats/{id}/leave: delete: tags: - talk and channel participants summary: '27 / Выход из беседы или канала' description: |- - Удаляет себя из беседы или канала. Доступно только авторизованным. + Параметры запроса отсутствуют. security: - Token: [ ] parameters: @@ -354,35 +443,78 @@ paths: type: integer responses: '200': - description: 'Успешно отписан' + description: 'Успешно отписан. Тело ответа отсутствует' + '400': + description: 'Нельзя покинуть персональный чат' content: application/json: schema: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: 'Ошибка удаления из беседы или канала (Например, не подписан на данную беседу или канал)' + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' content: application/json: schema: - $ref: '#/components/schemas/BadRequest' - '401': - description: Пользователь не авторизован' + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /messages/{id}/thread: + post: + tags: + - comments + summary: Создание нового треда + description: | + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '200': + description: Тред успешно создан или возвращены данные существующего треда. content: application/json: schema: - $ref: '#/components/schemas/AuthenticationError' + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного треда. + chat_id: + type: integer + description: Идентификатор чата треда. + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. '404': - description: 'Беседа или канал не существует' + description: Сообщение не найдено. content: application/json: schema: $ref: '#/components/schemas/NotFound' - /messages/{id}/thread: - delete: - tags: - - comments - summary: '28 / Новый тред' - description: 'Информация будет добавлена позже.' + '400': + description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' /messages: post: tags: @@ -409,8 +541,99 @@ paths: post: tags: - reactions to messages - summary: '38 / Добавление реакции' - description: 'Информация будет добавлена позже.' + operationId: postMessageReactions + summary: Добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + description: Emoji в строковом формате для добавления реакции. + required: + - code + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + blank_field: + summary: Поле code пустое + value: + error: blank + exclusion: + summary: Недопустимое значение эмодзи + value: + error: exclusion + + "403": + description: Превышение лимитов по реакциям. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + user_limit: + summary: Превышен лимит уникальных реакций пользователя + value: + error: user_limit + message: "Вы можете добавить не более 20 уникальных реакций." + unique_limit: + summary: Превышен лимит уникальных реакций на сообщение + value: + error: unique_limit + message: "Сообщение может содержать не более 30 уникальных реакций." + general_limit: + summary: Превышен общий лимит реакций на сообщение + value: + error: general_limit + message: "Сообщение может содержать не более 1000 реакций." + + "404": + description: Сообщение не найдено. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Сообщение не найдено. + examples: + not_found: + summary: Сообщение не существует + value: + error: not_found delete: tags: - reactions to messages @@ -474,8 +697,124 @@ paths: post: tags: - reminders - summary: '42 / Новое напоминание' - description: 'Информация будет добавлена позже.' + summary: 'Метод для создания нового напоминания.' + description: | + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + kind: + type: string + description: Тип + content: + type: string + description: Описание + due_at: + type: string + format: date-time + description: Срок выполнения (ISO-8601) + priority: + type: integer + description: Приоритет + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + performer_ids: + type: array + items: + type: integer + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + + '400': + description: Ошибка запроса + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки components: schemas: @@ -652,16 +991,89 @@ components: type: string message: type: string - AuthenticationError: + ErrorsCode: + description: Bad Request type: object properties: - detail: - description: 'Описание ошибки' - example: "Учетные данные не были предоставлены." + key: + type: string + value: + type: string + message: + type: string + code: type: string + payload: + type: object + Chat: + type: object + description: Беседа или канал + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + name: + type: string + description: Название + example: 🤿 aqua + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + member_ids: + type: array + description: Массив идентификаторов пользователей, участников + items: + type: integer + example: + - 185 + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (false) или открытый (true)' + example: false + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer securitySchemes: Token: description: 'Авторизация по токену.
Все запросы от имени пользователя должны выполняться с заголовком "Authorization: Token TOKENVALUE"' type: http - scheme: token + scheme: token \ No newline at end of file From 02e3a2d9104b2feaecbc747989fc034d82eb255e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Tue, 17 Dec 2024 20:07:34 +0300 Subject: [PATCH 049/296] List-of-employee-tags --- openapi.yaml | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d6708ce..a3dabe2 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -282,8 +282,44 @@ paths: get: tags: - tags - summary: '13 / Список тегов сотрудников' - description: 'Информация будет добавлена позже.' + summary: Список тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + '422': + description: Поле имеет недопустимое значение + content: + application/json: + schema: + $ref: '#/components/schemas/Exclusion' /group_tags/{id}/users: get: tags: From 1781122aa6863f9abb5f28e2d78a8349243b574a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 20:12:29 +0300 Subject: [PATCH 050/296] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20endpoints=20GET=20/messages=20=D0=B8=20GET?= =?UTF-8?q?=20/messages/{id}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 135 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 21 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d0f2398..e91c02d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -339,6 +339,11 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' + example: + message: + entity_type: discussion + entity_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': content: @@ -348,6 +353,19 @@ paths: properties: data: $ref: '#/components/schemas/Message' + example: + data: + id: 194275, + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + thread: null + forwarding: null + parent_message_id: null '404': description: Not Found content: @@ -374,14 +392,106 @@ paths: get: tags: - messages - summary: '32 / Список сообщений чата' - description: 'Информация будет добавлена позже.' + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + parameters: + - name: chat_id + in: path + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: | + Количество возвращаемых сущностей за один запрос + (по умолчанию 25, максимум 50) + schema: + title: per + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + schema: + title: page + type: integer + default: 1 + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + detail: "Не удалось найти" + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorModel' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + detail: Поле не может быть пустым + INVALID FIELD VALUE: + summary: invalid field value + value: + detail: Поле имеет недопустимое значение /messages/{id}: get: tags: - messages - summary: '31 / Информация о сообщении' - description: 'Информация будет добавлена позже.' + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + detail: "Не удалось найти" put: tags: - messages @@ -667,10 +777,6 @@ components: title: Link Preview type: boolean default: false - example: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) Message: type: object properties: @@ -772,19 +878,6 @@ components: type: integer nullable: true default: null - example: - id: 194275, - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null Reaction: type: object properties: From bfbeae86551839a5f62049e953f7d5437d6c62bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 17 Dec 2024 20:55:40 +0300 Subject: [PATCH 051/296] =?UTF-8?q?=D0=9F=D0=BE=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D1=8B=20?= =?UTF-8?q?=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20=D0=B2=20=D1=83=D0=B4?= =?UTF-8?q?=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B8=20=D1=80=D0=B5=D0=B0=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 61 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 17c843e..f44fe20 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -637,18 +637,44 @@ paths: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. examples: blank_field: summary: Поле code пустое value: - error: blank + errors: + - key: "code" + value: "" + message: "Поле не может быть пустым" + code: "blank" exclusion: summary: Недопустимое значение эмодзи value: - error: exclusion + errors: + - key: "code" + value: "invalid_emoji" + message: "Поле имеет недопустимое значение" + code: "exclusion" "404": description: Сообщение или реакция не найдены. @@ -657,14 +683,31 @@ paths: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object examples: not_found: summary: Сообщение или реакция не найдены value: - error: not_found + errors: + - key: "reaction" + value: "😊" + message: "Не удалось найти реакцию" + code: "not_found" get: tags: - reactions to messages From ad90de2f1ec8b696c48cb0830b4d537b019f516f Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 23:04:46 +0500 Subject: [PATCH 052/296] =?UTF-8?q?#17=20/=20=D0=9D=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B1=D0=B5=D1=81=D0=B5=D0=B4=D0=B0=20=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=BA=D0=B0=D0=BD=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d6708ce..8187b5f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -336,8 +336,58 @@ paths: post: tags: - chats and channels - summary: '17 / Новая беседа или канал' - description: 'Информация будет добавлена позже.' + operationId: createChat + summary: Новая беседа или канал + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/QueryChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + blank: + description: Обязательное поле (не может быть пустым) + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + not_found: + description: Не удалось найти + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) get: tags: - chats and channels @@ -1029,6 +1079,32 @@ components: type: string description: Ссылка на Видеочат example: 'https://meet.pachca.com/aqua-94bb21b5' + QueryChat: + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. From d061ee3f14907317ee45d7203f09578b00573a1a Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 23:54:00 +0500 Subject: [PATCH 053/296] =?UTF-8?q?#19=20=D0=A1=D0=BF=D0=B8=D1=81=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=B1=D0=B5=D1=81=D0=B5=D0=B4=20=D0=B8=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index c75b780..88c365d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -341,8 +341,109 @@ paths: get: tags: - chats and channels - summary: '19 / Список бесед и каналов' - description: 'Информация будет добавлена позже.' + operationId: getChats + summary: Список бесед и каналов + description: Получения списка бесед и каналов по заданным параметрам. + parameters: + - name: 'sort[{field}]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + - name: per + in: query + required: false + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + required: false + description: Страница выборки (по умолчанию 1) + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + not_found: + description: Не удалось найти + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) /chats/{id}: get: tags: From 3c5b5600caa180a4a90039a0c23b8d2a10ee36fd Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 23:57:28 +0500 Subject: [PATCH 054/296] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20=D0=B8=20=D1=81=D1=85?= =?UTF-8?q?=D0=B5=D0=BC=D1=83=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=80=D1=83=D1=87=D0=BA=D0=B8=20/chats/{i?= =?UTF-8?q?d}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 88c365d..d58e63f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -448,7 +448,7 @@ paths: get: tags: - chats and channels - operationId: getChatInfo + operationId: getChat summary: Информация о беседе или канале description: | Получения информации о беседе или канале. @@ -471,11 +471,14 @@ paths: data: $ref: '#/components/schemas/Chat' '404': - description: Не удалось найти + description: Запрашиваемый ресурс не существует content: application/json: schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/ErrorsCode' + examples: + not_found: + description: Не удалось найти /chats/{id}/members: post: tags: From 84f8248b746e012289c8f9193bdd458c7e5e5140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Tue, 17 Dec 2024 22:07:57 +0300 Subject: [PATCH 055/296] Corrected error schema --- openapi.yaml | 69 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index a3dabe2..988c69f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -272,12 +272,38 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - '404': - description: Тег не найден + "404": + description: Тег не найден. content: application/json: schema: - $ref: '#/components/schemas/NotFound' + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Тег не найден. + value: + errors: + - key: "id" + value: "100500" + message: "Не удалось найти тег" + code: "not_found" /group_tags: get: tags: @@ -314,12 +340,43 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - '422': - description: Поле имеет недопустимое значение + "400": + description: Ошибка валидации запроса. content: application/json: schema: - $ref: '#/components/schemas/Exclusion' + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + exclusion: + summary: Недопустимое значение количество возвращаемых сущностей за один запрос + value: + errors: + - key: "per" + value: "51" + message: "Поле имеет недопустимое значение" + code: "exclusion" /group_tags/{id}/users: get: tags: From 97d5bced2fec0b0de3099904911087104df45faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D0=BE=D1=80=D0=B0?= Date: Wed, 18 Dec 2024 00:36:28 +0300 Subject: [PATCH 056/296] feature 23 add tags 00:36 --- openapi.yaml | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d94d2bb..95f66ff 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -471,9 +471,49 @@ paths: /chats/{id}/members: post: tags: - - talk and channel participants - summary: '23 / Добавление пользователей' - description: 'Информация будет добавлена позже.' + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов пользователей, которые станут участниками + content: + application/json: + schema: + required: + - member_ids + type: object + properties: + member_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + responses: + '201': + description: Пользователи добавлены + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' /chats/{id}/group_tags: post: tags: From 5a152be61d40121161c6a4f9527f645ee36cb9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Wed, 18 Dec 2024 13:03:49 +0300 Subject: [PATCH 057/296] 44 --- openapi.yaml | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d94d2bb..7979bca 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -85,14 +85,16 @@ paths: post: tags: - common methods - summary: '44 / Получение подписи, ключа и других параметров' - description: 'Информация будет добавлена позже.' - /direct_url (полученный в ответе на запрос /uploads): - post: - tags: - - common methods - summary: '45 / Загрузка файла' - description: 'Информация будет добавлена позже.' + summary: Получение подписи и ключа для загрузки файла + description: Возвращает параметры, необходимые для безопасной загрузки файла. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' /users: get: tags: @@ -1074,6 +1076,27 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. + FileResponse: + type: object + properties: + Content-Disposition: + type: string + acl: + type: string + policy: + type: string + x-amz-credential: + type: string + x-amz-algorithm: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + key: + type: string + direct_url: + type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' From 23640b833d34dd4f5e109afffc91df04ace2ddad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Wed, 18 Dec 2024 13:08:32 +0300 Subject: [PATCH 058/296] 45 --- openapi.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 7979bca..2c804aa 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -95,6 +95,22 @@ paths: application/json: schema: $ref: '#/components/schemas/FileResponse' + /direct_url: + post: + tags: + - common methods + summary: Получение URL для загрузки + description: Отправляет запрос для получения URL для безопасной загрузки файла. + operationId: getDirectUrl + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + responses: + '204': + description: Успешный запрос. /users: get: tags: From 7390fd552705eb51f86009ed8c7723826c6d5853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=9C=D0=B0=D0=BB=D1=8B=D0=B3=D0=B8=D0=BD?= Date: Wed, 18 Dec 2024 15:15:50 +0500 Subject: [PATCH 059/296] add first commit --- openapi.yaml | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index d6708ce..a534b42 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -430,7 +430,36 @@ paths: tags: - talk and channel participants summary: '27 / Выход из беседы или канала' - description: 'Информация будет добавлена позже.' + description: |- + Параметры запроса отсутствуют. + security: + - Token: [ ] + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '200': + description: Успешно отписан. Тело ответа отсутствует + '400': + description: Нельзя покинуть персональный чат + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' /messages/{id}/thread: post: tags: @@ -507,7 +536,51 @@ paths: tags: - messages summary: '33 / Редактирование сообщения' - description: 'Информация будет добавлена позже.' + description: Метод для редактирования сообщения или комментария. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EditMessages' + responses: + '200': + description: Успешно отредактировано + content: + application/json: + schema: + type: object + properties: + data: + type: array + description: Созданное сообщение + items: + $ref: '#/components/schemas/Messages' + '400': + description: Нельзя покинуть персональный чат + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' /messages/{id}/reactions: post: tags: @@ -1041,4 +1114,114 @@ components: description: Название тега users_count: description: Количество сотрудников, которые имеют этот тег - type: integer \ No newline at end of file + type: integer + Forwarding: + type: object + description: Информация о пересылаемом сообщении. Возвращается как null, если это сообщение не является пересылаемым с сохранением автора. + properties: + original_message_id: + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + type: integer + description: Идентификатор пользователя, создавшего оригинальное сообщение + original_created_at: + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + type: integer + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + type: integer + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + parent_message_id: + type: integer + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + EditFile: + type: array + description: Прикрепляемые файлы + items: + type: object + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + description: 'Тип файла: файл (file), изображение (image)' + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + File: + allOf: + - type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор файла + - $ref: '#/components/schemas/EditFile' + EditMessages: + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + properties: + content: + type: string + description: Текст сообщения + file: + $ref: '#/components/schemas/EditFile' + buttons: + type: array + description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. + items: + type: array + items: + type: object + properties: + text: + type: string + description: Текст, отображаемый на кнопке пользователю + url: + type: string + description: Ссылка, которая будет открыта по нажатию кнопки + data: + type: string + description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + Messages: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор сообщения + file: + $ref: '#/components/schemas/File' + thread: + type: object + description: Тред сообщения. Возвращается как null, если у сообщения нет комментариев. + properties: + id: + type: integer + description: Идентификатор треда + chat_id: + type: integer + description: Идентификатор чата треда (используется для отправки новых комментариев в тред и получения списка комментариев) + forwarding: + $ref: '#/components/schemas/Forwarding' + - $ref: '#/components/schemas/EditMessages' + securitySchemes: + Token: + description: 'Авторизация по токену.
+ Все запросы от имени пользователя должны выполняться с заголовком "Authorization: Token TOKENVALUE"' + type: http + scheme: token \ No newline at end of file From 4878352d0086d6be71b04b57873173f4ec4b76c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=9C=D0=B0=D0=BB=D1=8B=D0=B3=D0=B8=D0=BD?= Date: Wed, 18 Dec 2024 15:16:40 +0500 Subject: [PATCH 060/296] 33_1 --- openapi.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index a534b42..12566ac 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1224,4 +1224,5 @@ components: description: 'Авторизация по токену.
Все запросы от имени пользователя должны выполняться с заголовком "Authorization: Token TOKENVALUE"' type: http - scheme: token \ No newline at end of file + scheme: token + \ No newline at end of file From 3c44227530c457700b1cce7afe1e06f2fa04629f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Wed, 18 Dec 2024 18:35:39 +0300 Subject: [PATCH 061/296] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=81=D1=85=D0=B5=D0=BC=D1=8B=20Errors=20?= =?UTF-8?q?=D0=B8=20Buttons,=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D1=8B?= =?UTF-8?q?=20=D1=82=D0=B5=D0=BB=D0=B0=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D0=B0,=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B8=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20=D0=B2=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=D1=85=20POST=20/message,=20GET?= =?UTF-8?q?=20/message,=20GET=20/message/{id}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 197 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 33 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index e91c02d..9d4e408 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -355,7 +355,7 @@ paths: $ref: '#/components/schemas/Message' example: data: - id: 194275, + id: 194275 entity_type: discussion entity_id: 198 chat_id: 198 @@ -363,6 +363,7 @@ paths: user_id: 12 created_at: 2020-06-08T09:32:57.000Z files: [] + buttons: [] thread: null forwarding: null parent_message_id: null @@ -371,24 +372,36 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Errors' example: - detail: "Не удалось найти" + errors: + - key: entyti_id + value: 1 + message: Не удалось найти + code: not_found '400': description: Bad Request content: application/json: schema: - $ref: '#/components/schemas/ErrorModel' + $ref: '#/components/schemas/Error' examples: REQUIRED FIELD BLANK: summary: required fields blank value: - detail: Поле не может быть пустым + errors: + - key: content + value: null + message: Поле не может быть пустым + code: blank INVALID FIELD VALUE: summary: invalid field value value: - detail: Поле имеет недопустимое значение + errors: + - key: entity_type + value: chat + message: Поле имеет недопустимое значение + code: exclusion get: tags: - messages @@ -400,6 +413,7 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + operationId: getListMessage parameters: - name: chat_id in: path @@ -436,29 +450,81 @@ paths: type: array items: $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null '404': description: Not Found content: application/json: schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Error' example: - detail: "Не удалось найти" + errors: + - key: chat_id + value: 1 + message: Не удалось найти + code: not_found '400': description: Bad Request content: application/json: schema: - $ref: '#/components/schemas/ErrorModel' + $ref: '#/components/schemas/Error' examples: REQUIRED FIELD BLANK: summary: required fields blank value: - detail: Поле не может быть пустым + errors: + - key: chat_id + value: null + message: Поле не может быть пустым + code: blank INVALID FIELD VALUE: summary: invalid field value value: - detail: Поле имеет недопустимое значение + errors: + - key: chat_id + value: chat + message: Поле имеет недопустимое значение + code: exclusion /messages/{id}: get: tags: @@ -468,6 +534,7 @@ paths: Метод для получения информации о сообщении. Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage parameters: - name: id in: path @@ -484,6 +551,33 @@ paths: properties: data: $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 '404': description: Not Found content: @@ -491,7 +585,11 @@ paths: schema: $ref: '#/components/schemas/NotFound' example: - detail: "Не удалось найти" + errors: + - key: id + value: 0 + message: Не удалось найти + code: not_found put: tags: - messages @@ -697,27 +795,54 @@ components: format: date-time description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ nullable: true - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string - ErrorModel: - title: ErrorModel - required: - - detail - type: object - properties: - detail: - title: Detail - anyOf: - - type: string - - type: object - additionalProperties: - type: string + Errors: + title: Errors + type: array + items: + title: Error + type: object + properties: + key: + title: key + type: string + value: + title: value + type: string + message: + title: message + type: string + code: + title: code + type: string + payload: + title: payload + type: object + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 CreateMessage: type: object required: @@ -764,6 +889,9 @@ components: size: title: Size type: integer + buttons: + title: buttons + $ref: '#/components/schemas/Buttons' parent_message_id: title: Parent Massage Id type: integer @@ -831,6 +959,9 @@ components: url: title: Url type: string + buttons: + title: buttons + $ref: '#/components/schemas/Buttons' thread: title: Thread type: object From 143fe2bcc01f7328fbbecaae58aef8657a5fe9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Thu, 19 Dec 2024 12:35:20 +0300 Subject: [PATCH 062/296] CODE --- openapi.yaml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 2c804aa..8cbffe5 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -105,9 +105,9 @@ paths: requestBody: required: true content: - application/json: + multipart/form-data: schema: - $ref: '#/components/schemas/FileResponse' + $ref: '#/components/schemas/DirectResponse' responses: '204': description: Успешный запрос. @@ -1113,6 +1113,27 @@ components: type: string direct_url: type: string + DirectResponse: + type: object + properties: + Content-Disposition: + type: string + acl: + type: string + policy: + type: string + x-amz-credential: + type: string + x-amz-algorithm: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + key: + type: string + file: + type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' From b6a6b8dab2268bb098016001ccd776ac7f4baf8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Thu, 19 Dec 2024 12:37:47 +0300 Subject: [PATCH 063/296] CODE --- openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 8cbffe5..c8b6e0a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1133,7 +1133,7 @@ components: key: type: string file: - type: string + type: file Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' From 6a2139bf176542c7b23c2495f4318f5c7b19e2bd Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:02:13 +0300 Subject: [PATCH 064/296] Update openapi.yaml --- openapi.yaml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 7766abf..ed3c794 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -437,12 +437,12 @@ paths: type: array items: $ref: '#/components/schemas/BaseEmployee' - '422': + '400': description: Поле имеет недопустимое значение content: application/json: schema: - $ref: '#/components/schemas/Exclusion' + $ref: '#/components/schemas/BadRequest' /chats: post: tags: @@ -580,11 +580,9 @@ paths: delete: tags: - talk and channel participants - summary: '27 / Выход из беседы или канала' + summary: 'Выход из беседы или канала' description: |- - Параметры запроса отсутствуют. - security: - - Token: [ ] + Метод для самостоятельного выхода из беседы или канала. parameters: - name: id in: path @@ -702,6 +700,7 @@ paths: content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': + description: Successful content: application/json: schema: @@ -740,7 +739,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/BadRequest' examples: REQUIRED FIELD BLANK: summary: required fields blank @@ -772,7 +771,7 @@ paths: operationId: getListMessage parameters: - name: chat_id - in: path + in: query description: Идентификатор чата (беседа, канал, диалог или чат треда) required: true schema: @@ -797,6 +796,7 @@ paths: default: 1 responses: '200': + description: Successful content: application/json: schema: @@ -851,7 +851,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/NotFound' example: errors: - key: chat_id @@ -863,7 +863,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: '#/components/schemas/BadRequest' examples: REQUIRED FIELD BLANK: summary: required fields blank @@ -900,6 +900,7 @@ paths: type: integer responses: '200': + description: Successfull content: application/json: schema: @@ -1436,7 +1437,7 @@ components: key: type: string file: - type: file + type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1844,4 +1845,4 @@ components: type: http scheme: bearer security: - - bearerAuth: [] \ No newline at end of file + - bearerAuth: [] From eaa07e3598bfb6433ee4ecc32303cd2c877b19d3 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Thu, 19 Dec 2024 20:02:06 +0500 Subject: [PATCH 065/296] 33_2 --- openapi.yaml | 1005 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 862 insertions(+), 143 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 12566ac..8aba4c3 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -85,14 +85,32 @@ paths: post: tags: - common methods - summary: '44 / Получение подписи, ключа и других параметров' - description: 'Информация будет добавлена позже.' - /direct_url (полученный в ответе на запрос /uploads): + summary: Получение подписи и ключа для загрузки файла + description: Возвращает параметры, необходимые для безопасной загрузки файла. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + /direct_url: post: tags: - common methods - summary: '45 / Загрузка файла' - description: 'Информация будет добавлена позже.' + summary: Получение URL для загрузки + description: Отправляет запрос для получения URL для безопасной загрузки файла. + operationId: getDirectUrl + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + responses: + '204': + description: Успешный запрос. /users: get: tags: @@ -272,18 +290,111 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - '404': - description: Тег не найден + "404": + description: Тег не найден. content: application/json: schema: - $ref: '#/components/schemas/NotFound' + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Тег не найден. + value: + errors: + - key: "id" + value: "100500" + message: "Не удалось найти тег" + code: "not_found" /group_tags: get: tags: - tags - summary: '13 / Список тегов сотрудников' - description: 'Информация будет добавлена позже.' + summary: Список тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + exclusion: + summary: Недопустимое значение количество возвращаемых сущностей за один запрос + value: + errors: + - key: "per" + value: "51" + message: "Поле имеет недопустимое значение" + code: "exclusion" /group_tags/{id}/users: get: tags: @@ -326,12 +437,12 @@ paths: type: array items: $ref: '#/components/schemas/BaseEmployee' - '422': + '400': description: Поле имеет недопустимое значение content: application/json: schema: - $ref: '#/components/schemas/Exclusion' + $ref: '#/components/schemas/BadRequest' /chats: post: tags: @@ -378,9 +489,49 @@ paths: /chats/{id}/members: post: tags: - - talk and channel participants - summary: '23 / Добавление пользователей' - description: 'Информация будет добавлена позже.' + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов пользователей, которые станут участниками + content: + application/json: + schema: + required: + - member_ids + type: object + properties: + member_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + responses: + '201': + description: Пользователи добавлены + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' /chats/{id}/group_tags: post: tags: @@ -429,23 +580,21 @@ paths: delete: tags: - talk and channel participants - summary: '27 / Выход из беседы или канала' + summary: 'Выход из беседы или канала' description: |- - Параметры запроса отсутствуют. - security: - - Token: [ ] + Метод для самостоятельного выхода из беседы или канала. parameters: - name: id in: path required: true - description: Уникальный идентификатор беседы или канала. + description: 'Уникальный идентификатор беседы или канала.' schema: type: integer responses: '200': - description: Успешно отписан. Тело ответа отсутствует + description: 'Успешно отписан. Тело ответа отсутствует' '400': - description: Нельзя покинуть персональный чат + description: 'Нельзя покинуть персональный чат' content: application/json: schema: @@ -519,19 +668,285 @@ paths: post: tags: - messages - summary: '30 / Новое сообщение' - description: 'Информация будет добавлена позже.' + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' + example: + message: + entity_type: discussion + entity_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + responses: + '201': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + example: + errors: + - key: entyti_id + value: 1 + message: Не удалось найти + code: not_found + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - key: content + value: null + message: Поле не может быть пустым + code: blank + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - key: entity_type + value: chat + message: Поле имеет недопустимое значение + code: exclusion get: tags: - messages - summary: '32 / Список сообщений чата' - description: 'Информация будет добавлена позже.' + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + operationId: getListMessage + parameters: + - name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: | + Количество возвращаемых сущностей за один запрос + (по умолчанию 25, максимум 50) + schema: + title: per + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + schema: + title: page + type: integer + default: 1 + responses: + '200': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + errors: + - key: chat_id + value: 1 + message: Не удалось найти + code: not_found + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - key: chat_id + value: null + message: Поле не может быть пустым + code: blank + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - key: chat_id + value: chat + message: Поле имеет недопустимое значение + code: exclusion /messages/{id}: get: tags: - messages - summary: '31 / Информация о сообщении' - description: 'Информация будет добавлена позже.' + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + description: Successfull + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + errors: + - key: id + value: 0 + message: Не удалось найти + code: not_found put: tags: - messages @@ -549,9 +964,10 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/EditMessages' + type: object + properties: + message: + $ref: '#/components/schemas/EditMessages' responses: '200': description: Успешно отредактировано @@ -564,7 +980,7 @@ paths: type: array description: Созданное сообщение items: - $ref: '#/components/schemas/Messages' + $ref: '#/components/schemas/Message' '400': description: Нельзя покинуть персональный чат content: @@ -681,8 +1097,106 @@ paths: delete: tags: - reactions to messages - summary: '39 / Удаление реакции' - description: 'Информация будет добавлена позже.' + operationId: deleteMessageReactions + summary: Удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: string + - name: code + in: query + required: true + description: Emoji, который нужно удалить. + schema: + type: string + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + blank_field: + summary: Поле code пустое + value: + errors: + - key: "code" + value: "" + message: "Поле не может быть пустым" + code: "blank" + exclusion: + summary: Недопустимое значение эмодзи + value: + errors: + - key: "code" + value: "invalid_emoji" + message: "Поле имеет недопустимое значение" + code: "exclusion" + + "404": + description: Сообщение или реакция не найдены. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Сообщение или реакция не найдены + value: + errors: + - key: "reaction" + value: "😊" + message: "Не удалось найти реакцию" + code: "not_found" get: tags: - reactions to messages @@ -927,6 +1441,48 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. + FileResponse: + type: object + properties: + Content-Disposition: + type: string + acl: + type: string + policy: + type: string + x-amz-credential: + type: string + x-amz-algorithm: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + key: + type: string + direct_url: + type: string + DirectResponse: + type: object + properties: + Content-Disposition: + type: string + acl: + type: string + policy: + type: string + x-amz-credential: + type: string + x-amz-algorithm: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + key: + type: string + file: + type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1012,6 +1568,274 @@ components: description: 'Описание ошибки' example: "Страница не найдена." type: string + Errors: + title: Errors + type: array + items: + title: Error + type: object + properties: + key: + title: key + type: string + value: + title: value + type: string + message: + title: message + type: string + code: + title: code + type: string + payload: + title: payload + type: object + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + CreateMessage: + type: object + required: + - entity_id + - content + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + files: + title: Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + name: + title: Name + type: string + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + size: + title: Size + type: integer + buttons: + title: buttons + $ref: '#/components/schemas/Buttons' + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false + EditMessages: + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + properties: + content: + type: string + description: Текст сообщения + default: Текст сообщения + files: + type: object + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - 'file' + - 'image' + size: + type: integer + default: 1234 + description: Размер файла в байтах, отображаемый пользователю + buttons: + type: array + description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. + items: + type: array + items: + type: object + properties: + text: + type: string + description: Текст, отображаемый на кнопке пользователю + url: + type: string + description: Ссылка, которая будет открыта по нажатию кнопки + data: + type: string + description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + Message: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + format: date-time + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + description: Размер файла в байтах, отображаемый пользователю + buttons: + title: buttons + $ref: '#/components/schemas/Buttons' + thread: + title: Thread + type: object + nullable: true + default: null + properties: + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + forwarding: + title: Forwarding + type: object + nullable: true + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. Reaction: type: object properties: @@ -1115,114 +1939,9 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer - Forwarding: - type: object - description: Информация о пересылаемом сообщении. Возвращается как null, если это сообщение не является пересылаемым с сохранением автора. - properties: - original_message_id: - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - type: integer - description: Идентификатор пользователя, создавшего оригинальное сообщение - original_created_at: - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - type: integer - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - type: integer - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - type: integer - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - EditFile: - type: array - description: Прикрепляемые файлы - items: - type: object - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - description: 'Тип файла: файл (file), изображение (image)' - size: - type: integer - description: Размер файла в байтах, отображаемый пользователю - File: - allOf: - - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор файла - - $ref: '#/components/schemas/EditFile' - EditMessages: - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - properties: - content: - type: string - description: Текст сообщения - file: - $ref: '#/components/schemas/EditFile' - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки - Messages: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор сообщения - file: - $ref: '#/components/schemas/File' - thread: - type: object - description: Тред сообщения. Возвращается как null, если у сообщения нет комментариев. - properties: - id: - type: integer - description: Идентификатор треда - chat_id: - type: integer - description: Идентификатор чата треда (используется для отправки новых комментариев в тред и получения списка комментариев) - forwarding: - $ref: '#/components/schemas/Forwarding' - - $ref: '#/components/schemas/EditMessages' securitySchemes: - Token: - description: 'Авторизация по токену.
- Все запросы от имени пользователя должны выполняться с заголовком "Authorization: Token TOKENVALUE"' + bearerAuth: type: http - scheme: token - \ No newline at end of file + scheme: bearer +security: + - bearerAuth: [] \ No newline at end of file From 41e7906f15c5b2f2654436d3fd1324046af20b01 Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 23:04:46 +0500 Subject: [PATCH 066/296] =?UTF-8?q?#17=20/=20=D0=9D=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B1=D0=B5=D1=81=D0=B5=D0=B4=D0=B0=20=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=BA=D0=B0=D0=BD=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index ed3c794..9d3c253 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -447,8 +447,58 @@ paths: post: tags: - chats and channels - summary: '17 / Новая беседа или канал' - description: 'Информация будет добавлена позже.' + operationId: createChat + summary: Новая беседа или канал + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/QueryChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + blank: + description: Обязательное поле (не может быть пустым) + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + not_found: + description: Не удалось найти + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) get: tags: - chats and channels @@ -1827,6 +1877,32 @@ components: type: string description: Ссылка на Видеочат example: 'https://meet.pachca.com/aqua-94bb21b5' + QueryChat: + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. From 99276b886997673a19b46f27473d875a7fd46c90 Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Thu, 19 Dec 2024 22:07:10 +0500 Subject: [PATCH 067/296] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=20=D1=81=D1=85=D0=B5=D0=BC=D1=83=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B0=20=D0=B8=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D1=86=D1=8B=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 55 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 9d3c253..e5bac0a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -457,7 +457,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/QueryChat' + type: object + properties: + chat: + $ref: '#/components/schemas/QueryChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -473,32 +476,76 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: blank: description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} too_long: description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} '404': description: Запрашиваемый ресурс не существует content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: not_found: description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} '422': description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: invalid: description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} get: tags: - chats and channels From 7f003c195d5ef916ef0f0accc56240669b2ad9da Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Thu, 19 Dec 2024 22:34:52 +0500 Subject: [PATCH 068/296] =?UTF-8?q?=D0=A3=D0=B1=D0=B5=D1=80=D0=B5=D1=82=20?= =?UTF-8?q?=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D1=85=D0=B5=D0=BC=D1=8B=20QueryChat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 5f76a8e..e5bac0a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1950,32 +1950,6 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false - QueryChat: - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. From b5fd0954e91947782f0146e91e439cb18b77d697 Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 23:54:00 +0500 Subject: [PATCH 069/296] =?UTF-8?q?#19=20=D0=A1=D0=BF=D0=B8=D1=81=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=B1=D0=B5=D1=81=D0=B5=D0=B4=20=D0=B8=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index e5bac0a..3982c2d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -549,8 +549,109 @@ paths: get: tags: - chats and channels - summary: '19 / Список бесед и каналов' - description: 'Информация будет добавлена позже.' + operationId: getChats + summary: Список бесед и каналов + description: Получения списка бесед и каналов по заданным параметрам. + parameters: + - name: 'sort[{field}]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + - name: per + in: query + required: false + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + required: false + description: Страница выборки (по умолчанию 1) + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + not_found: + description: Не удалось найти + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsCode' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) /chats/{id}: get: tags: From 0f9325b738db0a8f12c87295ce0bea93cefb0c25 Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Tue, 17 Dec 2024 23:57:28 +0500 Subject: [PATCH 070/296] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20=D0=B8=20=D1=81=D1=85?= =?UTF-8?q?=D0=B5=D0=BC=D1=83=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=80=D1=83=D1=87=D0=BA=D0=B8=20/chats/{i?= =?UTF-8?q?d}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 3982c2d..775642a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -656,7 +656,7 @@ paths: get: tags: - chats and channels - operationId: getChatInfo + operationId: getChat summary: Информация о беседе или канале description: | Получения информации о беседе или канале. @@ -679,11 +679,14 @@ paths: data: $ref: '#/components/schemas/Chat' '404': - description: Не удалось найти + description: Запрашиваемый ресурс не существует content: application/json: schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/ErrorsCode' + examples: + not_found: + description: Не удалось найти /chats/{id}/members: post: tags: From f00b3b733bb4eaac777bf3f148e056655b12ebe7 Mon Sep 17 00:00:00 2001 From: Denis Lopin Date: Thu, 19 Dec 2024 23:38:18 +0500 Subject: [PATCH 071/296] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=20query-=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=20'sort[id]',=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D1=8B=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 58 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 775642a..d098465 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -553,7 +553,7 @@ paths: summary: Список бесед и каналов description: Получения списка бесед и каналов по заданным параметрам. parameters: - - name: 'sort[{field}]' + - name: 'sort[id]' in: query required: false description: | @@ -565,6 +565,7 @@ paths: enum: - desc - asc + default: desc - name: per in: query required: false @@ -628,30 +629,67 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/ErrorsCode' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} '404': description: Запрашиваемый ресурс не существует content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: not_found: description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} '422': description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: invalid: description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}: get: tags: @@ -683,10 +721,20 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: not_found: description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /chats/{id}/members: post: tags: From 485d3696a019909b0b00dcd215d63d3d614b3b4c Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:06:23 +0300 Subject: [PATCH 072/296] Update openapi.yaml --- openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 8aba4c3..2ba786b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -950,7 +950,7 @@ paths: put: tags: - messages - summary: '33 / Редактирование сообщения' + summary: Редактирование сообщения description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1944,4 +1944,4 @@ components: type: http scheme: bearer security: - - bearerAuth: [] \ No newline at end of file + - bearerAuth: [] From 1ef59369c508fae97ccca93514ff28f28764aac0 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 23 Dec 2024 23:16:30 +0300 Subject: [PATCH 073/296] generate code --- openapi.yaml | 3 +- pachca-api-open-api-3-0-client/.gitignore | 23 + pachca-api-open-api-3-0-client/README.md | 124 ++ .../__init__.py | 8 + .../api/__init__.py | 1 + .../api/chats_and_channels/__init__.py | 0 .../api/chats_and_channels/create_chat.py | 128 ++ .../api/chats_and_channels/get_chat.py | 108 + .../api/chats_and_channels/get_chats.py | 188 ++ .../api/comments/__init__.py | 0 .../api/comments/create_thread.py | 113 ++ .../api/common_methods/__init__.py | 0 .../api/common_methods/get_common_methods.py | 116 ++ .../api/common_methods/get_direct_url.py | 79 + .../api/common_methods/get_uploads.py | 88 + .../api/employees/__init__.py | 0 .../api/employees/get_employee.py | 108 + .../api/employees/get_employees.py | 127 ++ .../api/messages/__init__.py | 0 .../api/messages/create_message.py | 150 ++ .../api/messages/get_list_message.py | 147 ++ .../api/messages/get_message.py | 110 + .../api/messages/put_messages_id.py | 137 ++ .../api/reactions_to_messages/__init__.py | 0 .../delete_message_reactions.py | 126 ++ .../get_message_reactions.py | 130 ++ .../post_message_reactions.py | 143 ++ .../api/reminders/__init__.py | 0 .../api/reminders/post_tasks.py | 126 ++ .../api/status/__init__.py | 0 .../api/status/del_status.py | 58 + .../api/status/get_status.py | 88 + .../api/status/put_status.py | 116 ++ .../api/tags/__init__.py | 0 .../api/tags/get_tag.py | 106 + .../api/tags/get_tags.py | 123 ++ .../api/tags/get_tags_employees.py | 130 ++ .../talk_and_channel_participants/__init__.py | 0 .../delete_chats_id_leave.py | 118 ++ .../post_members_to_chats.py | 126 ++ .../post_tags_to_chats.py | 126 ++ .../pachca_api_open_api_3_0_client/client.py | 1783 +++++++++++++++++ .../pachca_api_open_api_3_0_client/errors.py | 16 + .../models/__init__.py | 189 ++ .../models/bad_request.py | 67 + .../models/base_employee.py | 186 ++ .../base_employee_custom_properties_item.py | 85 + .../models/button.py | 78 + .../models/chat.py | 162 ++ .../models/create_chat_body.py | 71 + .../models/create_chat_response_201.py | 71 + .../models/create_chat_response_400.py | 74 + .../models/create_chat_response_404.py | 74 + .../models/create_chat_response_422.py | 74 + .../models/create_message.py | 178 ++ .../models/create_message_body.py | 71 + .../models/create_message_entity_type.py | 10 + .../models/create_message_files_item.py | 84 + .../create_message_files_item_file_type.py | 9 + .../models/create_message_response_201.py | 71 + .../models/create_thread_response_200.py | 71 + .../models/create_thread_response_200_data.py | 104 + .../delete_message_reactions_response_400.py | 76 + ...sage_reactions_response_400_errors_item.py | 111 + ...ctions_response_400_errors_item_payload.py | 43 + .../delete_message_reactions_response_404.py | 76 + ...sage_reactions_response_404_errors_item.py | 111 + ...ctions_response_404_errors_item_payload.py | 43 + .../models/direct_response.py | 195 ++ .../models/edit_messages.py | 113 ++ .../models/edit_messages_buttons_item_item.py | 76 + .../models/edit_messages_files.py | 95 + .../models/edit_messages_files_file_type.py | 9 + .../models/employee.py | 275 +++ .../models/error.py | 107 + .../models/error_payload.py | 43 + .../models/errors_code.py | 108 + .../models/errors_code_payload.py | 43 + .../models/file_response.py | 130 ++ .../models/get_chat_response_200.py | 71 + .../models/get_chat_response_404.py | 74 + .../models/get_chats_availability.py | 9 + .../models/get_chats_response_200.py | 74 + .../models/get_chats_response_400.py | 71 + .../models/get_chats_response_404.py | 74 + .../models/get_chats_response_422.py | 74 + .../models/get_chats_sortid.py | 9 + .../models/get_common_methods_response_200.py | 74 + .../models/get_employee_response_200.py | 71 + .../models/get_employees_response_200.py | 74 + .../models/get_list_message_response_200.py | 74 + .../models/get_message_reactions_body.py | 68 + .../get_message_reactions_response_200.py | 74 + .../models/get_message_response_200.py | 71 + .../models/get_status_response_200.py | 88 + .../models/get_tag_response_200.py | 71 + .../models/get_tag_response_404.py | 74 + .../get_tag_response_404_errors_item.py | 107 + ...et_tag_response_404_errors_item_payload.py | 43 + .../models/get_tags_employees_response_200.py | 74 + .../models/get_tags_response_200.py | 74 + .../models/get_tags_response_400.py | 74 + .../get_tags_response_400_errors_item.py | 107 + ...t_tags_response_400_errors_item_payload.py | 43 + .../models/message.py | 272 +++ .../models/message_entity_type.py | 10 + .../models/message_files_item.py | 104 + .../models/message_files_item_file_type.py | 9 + .../models/message_forwarding.py | 153 ++ .../models/message_thread.py | 67 + .../models/not_found.py | 59 + .../models/post_members_to_chats_body.py | 69 + .../models/post_message_reactions_body.py | 58 + .../post_message_reactions_response_400.py | 58 + .../post_message_reactions_response_403.py | 58 + .../post_message_reactions_response_404.py | 58 + .../models/post_tags_to_chats_body.py | 58 + .../models/post_tasks_body.py | 71 + .../models/post_tasks_body_task.py | 123 ++ ..._tasks_body_task_custom_properties_item.py | 67 + .../models/post_tasks_response_201.py | 71 + .../models/post_tasks_response_201_data.py | 177 ++ ...esponse_201_data_custom_properties_item.py | 85 + .../models/post_tasks_response_400.py | 58 + .../models/put_messages_id_body.py | 72 + .../models/put_messages_id_response_200.py | 74 + .../models/put_status_response_201.py | 88 + .../models/query_chat.py | 91 + .../models/query_common_methods.py | 77 + .../models/query_status.py | 71 + .../models/query_status_status.py | 102 + .../models/reaction.py | 86 + .../models/status_type_0.py | 101 + .../models/tag.py | 77 + .../pachca_api_open_api_3_0_client/py.typed | 1 + .../pachca_api_open_api_3_0_client/types.py | 46 + pachca-api-open-api-3-0-client/pyproject.toml | 27 + pachca.py | 34 + script.py | 40 + templates/client.py.jinja | 133 ++ templates/endpoint_module.py.jinja | 125 ++ templates/macros/client_macros.py.jinja | 25 + 142 files changed, 13127 insertions(+), 1 deletion(-) create mode 100644 pachca-api-open-api-3-0-client/.gitignore create mode 100644 pachca-api-open-api-3-0-client/README.md create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py create mode 100644 pachca-api-open-api-3-0-client/pyproject.toml create mode 100644 pachca.py create mode 100644 script.py create mode 100644 templates/client.py.jinja create mode 100644 templates/endpoint_module.py.jinja create mode 100644 templates/macros/client_macros.py.jinja diff --git a/openapi.yaml b/openapi.yaml index 7a6d84a..f4d8491 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -138,7 +138,8 @@ paths: - name: query in: query description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), + email (электронная почта), phone_number (телефон) и nickname (никнейм)) required: false schema: type: string diff --git a/pachca-api-open-api-3-0-client/.gitignore b/pachca-api-open-api-3-0-client/.gitignore new file mode 100644 index 0000000..79a2c3d --- /dev/null +++ b/pachca-api-open-api-3-0-client/.gitignore @@ -0,0 +1,23 @@ +__pycache__/ +build/ +dist/ +*.egg-info/ +.pytest_cache/ + +# pyenv +.python-version + +# Environments +.env +.venv + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# JetBrains +.idea/ + +/coverage.xml +/.coverage diff --git a/pachca-api-open-api-3-0-client/README.md b/pachca-api-open-api-3-0-client/README.md new file mode 100644 index 0000000..3bb71ab --- /dev/null +++ b/pachca-api-open-api-3-0-client/README.md @@ -0,0 +1,124 @@ +# pachca-api-open-api-3-0-client +A client library for accessing PachcaAPI - OpenAPI 3.0 + +## Usage +First, create a client: + +```python +from pachca_api_open_api_3_0_client import Client + +client = Client(base_url="https://api.example.com") +``` + +If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: + +```python +from pachca_api_open_api_3_0_client import AuthenticatedClient + +client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") +``` + +Now call your endpoint and use your models: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +with client as client: + my_data: MyDataModel = get_my_data_model.sync(client=client) + # or if you need more info (e.g. status_code) + response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) +``` + +Or do the same thing with an async version: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +async with client as client: + my_data: MyDataModel = await get_my_data_model.asyncio(client=client) + response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) +``` + +By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl="/path/to/certificate_bundle.pem", +) +``` + +You can also disable certificate validation altogether, but beware that **this is a security risk**. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl=False +) +``` + +Things to know: +1. Every path/method combo becomes a Python module with four functions: + 1. `sync`: Blocking request that returns parsed data (if successful) or `None` + 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. + 1. `asyncio`: Like `sync` but async instead of blocking + 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking + +1. All path/query params, and bodies become method arguments. +1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) +1. Any endpoint which did not have a tag will be in `pachca_api_open_api_3_0_client.api.default` + +## Advanced customizations + +There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): + +```python +from pachca_api_open_api_3_0_client import Client + +def log_request(request): + print(f"Request event hook: {request.method} {request.url} - Waiting for response") + +def log_response(response): + request = response.request + print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") + +client = Client( + base_url="https://api.example.com", + httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, +) + +# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() +``` + +You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): + +```python +import httpx +from pachca_api_open_api_3_0_client import Client + +client = Client( + base_url="https://api.example.com", +) +# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. +client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) +``` + +## Building / publishing this package +This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: +1. Update the metadata in pyproject.toml (e.g. authors, version) +1. If you're using a private repository, configure it with Poetry + 1. `poetry config repositories. ` + 1. `poetry config http-basic. ` +1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` + +If you want to install this client into another project without publishing it (e.g. for development) then: +1. If that project **is using Poetry**, you can simply do `poetry add ` from that project +1. If that project is not using Poetry: + 1. Build a wheel with `poetry build -f wheel` + 1. Install that wheel from the other project `pip install ` diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py new file mode 100644 index 0000000..3a6c9f0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py @@ -0,0 +1,8 @@ +"""A client library for accessing PachcaAPI - OpenAPI 3.0""" + +from .client import AuthenticatedClient, Client + +__all__ = ( + "AuthenticatedClient", + "Client", +) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py new file mode 100644 index 0000000..81f9fa2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py @@ -0,0 +1 @@ +"""Contains methods for accessing the API""" diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py new file mode 100644 index 0000000..2ccc588 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -0,0 +1,128 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.create_chat_body import CreateChatBody +from ...models.create_chat_response_201 import CreateChatResponse201 +from ...models.create_chat_response_400 import CreateChatResponse400 +from ...models.create_chat_response_404 import CreateChatResponse404 +from ...models.create_chat_response_422 import CreateChatResponse422 +from ...types import Response + + +def _get_kwargs_createChat( + *, + body: CreateChatBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/chats", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_createChat( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createChat( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_createChat(client=client, response=response), + ) + + +async def asyncio_detailed_createChat( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + + kwargs = _get_kwargs_createChat( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_createChat(client=client, response=response) + + +async def createChat( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + + return ( + await asyncio_detailed_createChat( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py new file mode 100644 index 0000000..4cd7fd0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -0,0 +1,108 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_chat_response_200 import GetChatResponse200 +from ...models.get_chat_response_404 import GetChatResponse404 +from ...types import Response + + +def _get_kwargs_getChat( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/chats/{id}", + } + + return _kwargs + + +def _parse_response_getChat( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getChat( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getChat(client=client, response=response), + ) + + +async def asyncio_detailed_getChat( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatResponse200, GetChatResponse404]] + """ + + kwargs = _get_kwargs_getChat( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getChat(client=client, response=response) + + +async def getChat( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + + return ( + await asyncio_detailed_getChat( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py new file mode 100644 index 0000000..8b6f831 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -0,0 +1,188 @@ +import datetime +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_chats_availability import GetChatsAvailability +from ...models.get_chats_response_200 import GetChatsResponse200 +from ...models.get_chats_response_400 import GetChatsResponse400 +from ...models.get_chats_response_404 import GetChatsResponse404 +from ...models.get_chats_response_422 import GetChatsResponse422 +from ...models.get_chats_sortid import GetChatsSortid +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getChats( + *, + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + + params["sort[id]"] = json_sortid + + params["per"] = per + + params["page"] = page + + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + + params["availability"] = json_availability + + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params["last_message_at_after"] = json_last_message_at_after + + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params["last_message_at_before"] = json_last_message_at_before + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/chats", + "params": params, + } + + return _kwargs + + +def _parse_response_getChats( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getChats( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getChats(client=client, response=response), + ) + + +async def asyncio_detailed_getChats( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + + kwargs = _get_kwargs_getChats( + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getChats(client=client, response=response) + + +async def getChats( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + + return ( + await asyncio_detailed_getChats( + client=client, + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py new file mode 100644 index 0000000..d8561b6 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -0,0 +1,113 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.create_thread_response_200 import CreateThreadResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_createThread( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/thread", + } + + return _kwargs + + +def _parse_response_createThread( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createThread( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_createThread(client=client, response=response), + ) + + +async def asyncio_detailed_createThread( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + + kwargs = _get_kwargs_createThread( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_createThread(client=client, response=response) + + +async def createThread( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + + return ( + await asyncio_detailed_createThread( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py new file mode 100644 index 0000000..f0af81e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -0,0 +1,116 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from ...types import UNSET, Response + + +def _get_kwargs_getCommonMethods( + *, + entity_type: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["entity_type"] = entity_type + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/custom_properties", + "params": params, + } + + return _kwargs + + +def _parse_response_getCommonMethods( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getCommonMethods( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getCommonMethods(client=client, response=response), + ) + + +async def asyncio_detailed_getCommonMethods( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + + kwargs = _get_kwargs_getCommonMethods( + entity_type=entity_type, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getCommonMethods(client=client, response=response) + + +async def getCommonMethods( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + + return ( + await asyncio_detailed_getCommonMethods( + client=client, + entity_type=entity_type, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py new file mode 100644 index 0000000..e108675 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py @@ -0,0 +1,79 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.direct_response import DirectResponse +from ...types import Response + + +def _get_kwargs_getDirectUrl( + *, + body: DirectResponse, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/direct_url", + } + + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_getDirectUrl( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getDirectUrl( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getDirectUrl(client=client, response=response), + ) + + +async def asyncio_detailed_getDirectUrl( + *, + client: Union[AuthenticatedClient, Client], + body: DirectResponse, +) -> Response[Any]: + """Получение URL для загрузки + + Отправляет запрос для получения URL для безопасной загрузки файла. + + Args: + body (DirectResponse): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs_getDirectUrl( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getDirectUrl(client=client, response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py new file mode 100644 index 0000000..c8e98a3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -0,0 +1,88 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.file_response import FileResponse +from ...types import Response + + +def _get_kwargs_getUploads() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/uploads", + } + + return _kwargs + + +def _parse_response_getUploads( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getUploads( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[FileResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getUploads(client=client, response=response), + ) + + +async def asyncio_detailed_getUploads( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[FileResponse] + """ + + kwargs = _get_kwargs_getUploads() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getUploads(client=client, response=response) + + +async def getUploads( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + + return ( + await asyncio_detailed_getUploads( + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py new file mode 100644 index 0000000..2e806b4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -0,0 +1,108 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_employee_response_200 import GetEmployeeResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_getEmployee( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/users/{id}", + } + + return _kwargs + + +def _parse_response_getEmployee( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getEmployee( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getEmployee(client=client, response=response), + ) + + +async def asyncio_detailed_getEmployee( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetEmployeeResponse200, NotFound]] + """ + + kwargs = _get_kwargs_getEmployee( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getEmployee(client=client, response=response) + + +async def getEmployee( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + + return ( + await asyncio_detailed_getEmployee( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py new file mode 100644 index 0000000..9dfd7e4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -0,0 +1,127 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_employees_response_200 import GetEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getEmployees( + *, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params["query"] = query + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/users", + "params": params, + } + + return _kwargs + + +def _parse_response_getEmployees( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getEmployees( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[GetEmployeesResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getEmployees(client=client, response=response), + ) + + +async def asyncio_detailed_getEmployees( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + + kwargs = _get_kwargs_getEmployees( + per=per, + page=page, + query=query, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getEmployees(client=client, response=response) + + +async def getEmployees( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + + return ( + await asyncio_detailed_getEmployees( + client=client, + per=per, + page=page, + query=query, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py new file mode 100644 index 0000000..7a2dd69 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -0,0 +1,150 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.create_message_body import CreateMessageBody +from ...models.create_message_response_201 import CreateMessageResponse201 +from ...models.error import Error +from ...types import Response + + +def _get_kwargs_createMessage( + *, + body: CreateMessageBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/messages", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_createMessage( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + response_404.append(componentsschemas_errors_item) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createMessage( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_createMessage(client=client, response=response), + ) + + +async def asyncio_detailed_createMessage( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + """ + + kwargs = _get_kwargs_createMessage( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_createMessage(client=client, response=response) + + +async def createMessage( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + + return ( + await asyncio_detailed_createMessage( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py new file mode 100644 index 0000000..a97e96b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -0,0 +1,147 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_list_message_response_200 import GetListMessageResponse200 +from ...models.not_found import NotFound +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getListMessage( + *, + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["chat_id"] = chat_id + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/messages", + "params": params, + } + + return _kwargs + + +def _parse_response_getListMessage( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetListMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getListMessage( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getListMessage(client=client, response=response), + ) + + +async def asyncio_detailed_getListMessage( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs_getListMessage( + chat_id=chat_id, + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getListMessage(client=client, response=response) + + +async def getListMessage( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + + return ( + await asyncio_detailed_getListMessage( + client=client, + chat_id=chat_id, + per=per, + page=page, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py new file mode 100644 index 0000000..089a43f --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -0,0 +1,110 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_message_response_200 import GetMessageResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_getMessage( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}", + } + + return _kwargs + + +def _parse_response_getMessage( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getMessage( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getMessage(client=client, response=response), + ) + + +async def asyncio_detailed_getMessage( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs_getMessage( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getMessage(client=client, response=response) + + +async def getMessage( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + + return ( + await asyncio_detailed_getMessage( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py new file mode 100644 index 0000000..f71e737 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py @@ -0,0 +1,137 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.put_messages_id_body import PutMessagesIdBody +from ...models.put_messages_id_response_200 import PutMessagesIdResponse200 +from ...types import Response + + +def _get_kwargs_put_messages_id( + id: int, + *, + body: PutMessagesIdBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": f"/messages/{id}", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_put_messages_id( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = PutMessagesIdResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_put_messages_id( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_put_messages_id(client=client, response=response), + ) + + +async def asyncio_detailed_put_messages_id( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs_put_messages_id( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_put_messages_id(client=client, response=response) + + +async def put_messages_id( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PutMessagesIdResponse200, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed_put_messages_id( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py new file mode 100644 index 0000000..14bbc5d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -0,0 +1,126 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from ...types import UNSET, Response + + +def _get_kwargs_deleteMessageReactions( + id: str, + *, + code: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["code"] = code + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/messages/{id}/reactions", + "params": params, + } + + return _kwargs + + +def _parse_response_deleteMessageReactions( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_deleteMessageReactions( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_deleteMessageReactions(client=client, response=response), + ) + + +async def asyncio_detailed_deleteMessageReactions( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs_deleteMessageReactions( + id=id, + code=code, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_deleteMessageReactions(client=client, response=response) + + +async def deleteMessageReactions( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + + return ( + await asyncio_detailed_deleteMessageReactions( + id=id, + client=client, + code=code, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py new file mode 100644 index 0000000..52a534f --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -0,0 +1,130 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_message_reactions_body import GetMessageReactionsBody +from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_getMessageReactions( + id: int, + *, + body: GetMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_getMessageReactions( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getMessageReactions( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getMessageReactions(client=client, response=response), + ) + + +async def asyncio_detailed_getMessageReactions( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + """ + + kwargs = _get_kwargs_getMessageReactions( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getMessageReactions(client=client, response=response) + + +async def getMessageReactions( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + + return ( + await asyncio_detailed_getMessageReactions( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py new file mode 100644 index 0000000..a2b548d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -0,0 +1,143 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_message_reactions_body import PostMessageReactionsBody +from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from ...types import Response + + +def _get_kwargs_postMessageReactions( + id: str, + *, + body: PostMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_postMessageReactions( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_postMessageReactions( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_postMessageReactions(client=client, response=response), + ) + + +async def asyncio_detailed_postMessageReactions( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs_postMessageReactions( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_postMessageReactions(client=client, response=response) + + +async def postMessageReactions( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + + return ( + await asyncio_detailed_postMessageReactions( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py new file mode 100644 index 0000000..4e6b179 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py @@ -0,0 +1,126 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_tasks_body import PostTasksBody +from ...models.post_tasks_response_201 import PostTasksResponse201 +from ...models.post_tasks_response_400 import PostTasksResponse400 +from ...types import Response + + +def _get_kwargs_post_tasks( + *, + body: PostTasksBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tasks", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_post_tasks( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = PostTasksResponse400.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_post_tasks( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_post_tasks(client=client, response=response), + ) + + +async def asyncio_detailed_post_tasks( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PostTasksResponse201, PostTasksResponse400]] + """ + + kwargs = _get_kwargs_post_tasks( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_post_tasks(client=client, response=response) + + +async def post_tasks( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PostTasksResponse201, PostTasksResponse400] + """ + + return ( + await asyncio_detailed_post_tasks( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py new file mode 100644 index 0000000..a834ee3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py @@ -0,0 +1,58 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs_delStatus() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response_delStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_delStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_delStatus(client=client, response=response), + ) + + +async def asyncio_detailed_delStatus( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs_delStatus() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_delStatus(client=client, response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py new file mode 100644 index 0000000..9f6f7aa --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -0,0 +1,88 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_status_response_200 import GetStatusResponse200 +from ...types import Response + + +def _get_kwargs_getStatus() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response_getStatus( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getStatus( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[GetStatusResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getStatus(client=client, response=response), + ) + + +async def asyncio_detailed_getStatus( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetStatusResponse200] + """ + + kwargs = _get_kwargs_getStatus() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getStatus(client=client, response=response) + + +async def getStatus( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + + return ( + await asyncio_detailed_getStatus( + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py new file mode 100644 index 0000000..9714bfc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -0,0 +1,116 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.put_status_response_201 import PutStatusResponse201 +from ...models.query_status import QueryStatus +from ...types import Response + + +def _get_kwargs_putStatus( + *, + body: QueryStatus, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/profile/status", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_putStatus( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_putStatus( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_putStatus(client=client, response=response), + ) + + +async def asyncio_detailed_putStatus( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, PutStatusResponse201]] + """ + + kwargs = _get_kwargs_putStatus( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_putStatus(client=client, response=response) + + +async def putStatus( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + + return ( + await asyncio_detailed_putStatus( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py new file mode 100644 index 0000000..b478e3b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -0,0 +1,106 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_tag_response_200 import GetTagResponse200 +from ...models.get_tag_response_404 import GetTagResponse404 +from ...types import Response + + +def _get_kwargs_getTag( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}", + } + + return _kwargs + + +def _parse_response_getTag( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getTag( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getTag(client=client, response=response), + ) + + +async def asyncio_detailed_getTag( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagResponse200, GetTagResponse404]] + """ + + kwargs = _get_kwargs_getTag( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getTag(client=client, response=response) + + +async def getTag( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + + return ( + await asyncio_detailed_getTag( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py new file mode 100644 index 0000000..858b178 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -0,0 +1,123 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_tags_response_200 import GetTagsResponse200 +from ...models.get_tags_response_400 import GetTagsResponse400 +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getTags( + *, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/group_tags", + "params": params, + } + + return _kwargs + + +def _parse_response_getTags( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getTags( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getTags(client=client, response=response), + ) + + +async def asyncio_detailed_getTags( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + + kwargs = _get_kwargs_getTags( + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getTags(client=client, response=response) + + +async def getTags( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + + return ( + await asyncio_detailed_getTags( + client=client, + per=per, + page=page, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py new file mode 100644 index 0000000..7c278da --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -0,0 +1,130 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getTagsEmployees( + id: int, + *, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}/users", + "params": params, + } + + return _kwargs + + +def _parse_response_getTagsEmployees( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getTagsEmployees( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_getTagsEmployees(client=client, response=response), + ) + + +async def asyncio_detailed_getTagsEmployees( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetTagsEmployeesResponse200]] + """ + + kwargs = _get_kwargs_getTagsEmployees( + id=id, + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_getTagsEmployees(client=client, response=response) + + +async def getTagsEmployees( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + + return ( + await asyncio_detailed_getTagsEmployees( + id=id, + client=client, + per=per, + page=page, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py new file mode 100644 index 0000000..8ea8285 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py @@ -0,0 +1,118 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...types import Response + + +def _get_kwargs_delete_chats_id_leave( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/chats/{id}/leave", + } + + return _kwargs + + +def _parse_response_delete_chats_id_leave( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_delete_chats_id_leave( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_delete_chats_id_leave(client=client, response=response), + ) + + +async def asyncio_detailed_delete_chats_id_leave( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs_delete_chats_id_leave( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_delete_chats_id_leave(client=client, response=response) + + +async def delete_chats_id_leave( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed_delete_chats_id_leave( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py new file mode 100644 index 0000000..d452a32 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -0,0 +1,126 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.post_members_to_chats_body import PostMembersToChatsBody +from ...types import Response + + +def _get_kwargs_postMembersToChats( + id: int, + *, + body: PostMembersToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/members", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_postMembersToChats( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_postMembersToChats( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_postMembersToChats(client=client, response=response), + ) + + +async def asyncio_detailed_postMembersToChats( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs_postMembersToChats( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_postMembersToChats(client=client, response=response) + + +async def postMembersToChats( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed_postMembersToChats( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py new file mode 100644 index 0000000..36b299e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -0,0 +1,126 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.post_tags_to_chats_body import PostTagsToChatsBody +from ...types import Response + + +def _get_kwargs_postTagsToChats( + id: int, + *, + body: PostTagsToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/group_tags", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_postTagsToChats( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_postTagsToChats( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_postTagsToChats(client=client, response=response), + ) + + +async def asyncio_detailed_postTagsToChats( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs_postTagsToChats( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response_postTagsToChats(client=client, response=response) + + +async def postTagsToChats( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed_postTagsToChats( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py new file mode 100644 index 0000000..9110b6a --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -0,0 +1,1783 @@ +import ssl +from typing import Any, Union, Optional + +from attrs import define, field, evolve +import httpx + + + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + ``token``: The token to use for authentication + + ``prefix``: The prefix to use for the Authorization header + + ``auth_header_name``: The name of the Authorization header + + + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class Pachca: + """Главный класс библиотеки.""" + + def __init__(self, base_url, token): + self.client = AuthenticatedClient(base_url=base_url, token=token) + + + + def _get_kwargs_createThread(id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} + return _kwargs + + def _parse_response_createThread(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createThread(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_createThread(client=client, response=response)) + + async def asyncio_detailed_createThread(id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + kwargs = _get_kwargs_createThread(id=id) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_createThread(client=client, response=response) + + async def createThread(id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + return (await asyncio_detailed_createThread(id=id, client=client)).parsed + + def _get_kwargs_getCommonMethods(*, entity_type: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['entity_type'] = entity_type + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} + return _kwargs + + def _parse_response_getCommonMethods(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getCommonMethods(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getCommonMethods(client=client, response=response)) + + async def asyncio_detailed_getCommonMethods(*, client: Union[AuthenticatedClient, Client], entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + kwargs = _get_kwargs_getCommonMethods(entity_type=entity_type) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getCommonMethods(client=client, response=response) + + async def getCommonMethods(*, client: Union[AuthenticatedClient, Client], entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + return (await asyncio_detailed_getCommonMethods(client=client, entity_type=entity_type)).parsed + + def _get_kwargs_getDirectUrl(*, body: DirectResponse) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} + _body = body.to_multipart() + _kwargs['files'] = _body + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_getDirectUrl(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getDirectUrl(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getDirectUrl(client=client, response=response)) + + async def asyncio_detailed_getDirectUrl(*, client: Union[AuthenticatedClient, Client], body: DirectResponse) -> Response[Any]: + """Получение URL для загрузки + + Отправляет запрос для получения URL для безопасной загрузки файла. + + Args: + body (DirectResponse): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + kwargs = _get_kwargs_getDirectUrl(body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getDirectUrl(client=client, response=response) + + def _get_kwargs_getUploads() -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} + return _kwargs + + def _parse_response_getUploads(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getUploads(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[FileResponse]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getUploads(client=client, response=response)) + + async def asyncio_detailed_getUploads(*, client: Union[AuthenticatedClient, Client]) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[FileResponse] + """ + kwargs = _get_kwargs_getUploads() + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getUploads(client=client, response=response) + + async def getUploads(*, client: Union[AuthenticatedClient, Client]) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + return (await asyncio_detailed_getUploads(client=client)).parsed + + def _get_kwargs_put_messages_id(id: int, *, body: PutMessagesIdBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_put_messages_id(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + if response.status_code == 200: + response_200 = PutMessagesIdResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_put_messages_id(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_put_messages_id(client=client, response=response)) + + async def asyncio_detailed_put_messages_id(id: int, *, client: Union[AuthenticatedClient, Client], body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + """ + kwargs = _get_kwargs_put_messages_id(id=id, body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_put_messages_id(client=client, response=response) + + async def put_messages_id(id: int, *, client: Union[AuthenticatedClient, Client], body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PutMessagesIdResponse200, list['ErrorsCode']] + """ + return (await asyncio_detailed_put_messages_id(id=id, client=client, body=body)).parsed + + def _get_kwargs_createMessage(*, body: CreateMessageBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_createMessage(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + response_404.append(componentsschemas_errors_item) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createMessage(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_createMessage(client=client, response=response)) + + async def asyncio_detailed_createMessage(*, client: Union[AuthenticatedClient, Client], body: CreateMessageBody) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + """создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + """ + kwargs = _get_kwargs_createMessage(body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_createMessage(client=client, response=response) + + async def createMessage(*, client: Union[AuthenticatedClient, Client], body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + """создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + return (await asyncio_detailed_createMessage(client=client, body=body)).parsed + + def _get_kwargs_getMessage(id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} + return _kwargs + + def _parse_response_getMessage(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getMessage(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getMessage(client=client, response=response)) + + async def asyncio_detailed_getMessage(id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + kwargs = _get_kwargs_getMessage(id=id) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getMessage(client=client, response=response) + + async def getMessage(id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + return (await asyncio_detailed_getMessage(id=id, client=client)).parsed + + def _get_kwargs_getListMessage(*, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['chat_id'] = chat_id + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} + return _kwargs + + def _parse_response_getListMessage(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetListMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getListMessage(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getListMessage(client=client, response=response)) + + async def asyncio_detailed_getListMessage(*, client: Union[AuthenticatedClient, Client], chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + """ + kwargs = _get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getListMessage(client=client, response=response) + + async def getListMessage(*, client: Union[AuthenticatedClient, Client], chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + return (await asyncio_detailed_getListMessage(client=client, chat_id=chat_id, per=per, page=page)).parsed + + def _get_kwargs_postTagsToChats(id: int, *, body: PostTagsToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_postTagsToChats(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postTagsToChats(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_postTagsToChats(client=client, response=response)) + + async def asyncio_detailed_postTagsToChats(id: int, *, client: Union[AuthenticatedClient, Client], body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + kwargs = _get_kwargs_postTagsToChats(id=id, body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_postTagsToChats(client=client, response=response) + + async def postTagsToChats(id: int, *, client: Union[AuthenticatedClient, Client], body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + return (await asyncio_detailed_postTagsToChats(id=id, client=client, body=body)).parsed + + def _get_kwargs_delete_chats_id_leave(id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} + return _kwargs + + def _parse_response_delete_chats_id_leave(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_delete_chats_id_leave(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_delete_chats_id_leave(client=client, response=response)) + + async def asyncio_detailed_delete_chats_id_leave(id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + kwargs = _get_kwargs_delete_chats_id_leave(id=id) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_delete_chats_id_leave(client=client, response=response) + + async def delete_chats_id_leave(id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + return (await asyncio_detailed_delete_chats_id_leave(id=id, client=client)).parsed + + def _get_kwargs_postMembersToChats(id: int, *, body: PostMembersToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_postMembersToChats(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postMembersToChats(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_postMembersToChats(client=client, response=response)) + + async def asyncio_detailed_postMembersToChats(id: int, *, client: Union[AuthenticatedClient, Client], body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + kwargs = _get_kwargs_postMembersToChats(id=id, body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_postMembersToChats(client=client, response=response) + + async def postMembersToChats(id: int, *, client: Union[AuthenticatedClient, Client], body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + return (await asyncio_detailed_postMembersToChats(id=id, client=client, body=body)).parsed + + def _get_kwargs_getChat(id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} + return _kwargs + + def _parse_response_getChat(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getChat(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getChat(client=client, response=response)) + + async def asyncio_detailed_getChat(id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatResponse200, GetChatResponse404]] + """ + kwargs = _get_kwargs_getChat(id=id) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getChat(client=client, response=response) + + async def getChat(id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + return (await asyncio_detailed_getChat(id=id, client=client)).parsed + + def _get_kwargs_createChat(*, body: CreateChatBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_createChat(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createChat(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_createChat(client=client, response=response)) + + async def asyncio_detailed_createChat(*, client: Union[AuthenticatedClient, Client], body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + kwargs = _get_kwargs_createChat(body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_createChat(client=client, response=response) + + async def createChat(*, client: Union[AuthenticatedClient, Client], body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + return (await asyncio_detailed_createChat(client=client, body=body)).parsed + + def _get_kwargs_getChats(*, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + params['sort[id]'] = json_sortid + params['per'] = per + params['page'] = page + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + params['availability'] = json_availability + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params['last_message_at_after'] = json_last_message_at_after + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params['last_message_at_before'] = json_last_message_at_before + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} + return _kwargs + + def _parse_response_getChats(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getChats(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getChats(client=client, response=response)) + + async def asyncio_detailed_getChats(*, client: Union[AuthenticatedClient, Client], sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + kwargs = _get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getChats(client=client, response=response) + + async def getChats(*, client: Union[AuthenticatedClient, Client], sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + return (await asyncio_detailed_getChats(client=client, sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed + + def _get_kwargs_getStatus() -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} + return _kwargs + + def _parse_response_getStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[GetStatusResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getStatus(client=client, response=response)) + + async def asyncio_detailed_getStatus(*, client: Union[AuthenticatedClient, Client]) -> Response[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetStatusResponse200] + """ + kwargs = _get_kwargs_getStatus() + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getStatus(client=client, response=response) + + async def getStatus(*, client: Union[AuthenticatedClient, Client]) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + return (await asyncio_detailed_getStatus(client=client)).parsed + + def _get_kwargs_putStatus(*, body: QueryStatus) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_putStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_putStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_putStatus(client=client, response=response)) + + async def asyncio_detailed_putStatus(*, client: Union[AuthenticatedClient, Client], body: QueryStatus) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, PutStatusResponse201]] + """ + kwargs = _get_kwargs_putStatus(body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_putStatus(client=client, response=response) + + async def putStatus(*, client: Union[AuthenticatedClient, Client], body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + return (await asyncio_detailed_putStatus(client=client, body=body)).parsed + + def _get_kwargs_delStatus() -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} + return _kwargs + + def _parse_response_delStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_delStatus(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_delStatus(client=client, response=response)) + + async def asyncio_detailed_delStatus(*, client: Union[AuthenticatedClient, Client]) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + kwargs = _get_kwargs_delStatus() + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_delStatus(client=client, response=response) + + def _get_kwargs_getTags(*, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} + return _kwargs + + def _parse_response_getTags(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTags(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getTags(client=client, response=response)) + + async def asyncio_detailed_getTags(*, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + kwargs = _get_kwargs_getTags(per=per, page=page) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getTags(client=client, response=response) + + async def getTags(*, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + return (await asyncio_detailed_getTags(client=client, per=per, page=page)).parsed + + def _get_kwargs_getTag(id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} + return _kwargs + + def _parse_response_getTag(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTag(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getTag(client=client, response=response)) + + async def asyncio_detailed_getTag(id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagResponse200, GetTagResponse404]] + """ + kwargs = _get_kwargs_getTag(id=id) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getTag(client=client, response=response) + + async def getTag(id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + return (await asyncio_detailed_getTag(id=id, client=client)).parsed + + def _get_kwargs_getTagsEmployees(id: int, *, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} + return _kwargs + + def _parse_response_getTagsEmployees(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTagsEmployees(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getTagsEmployees(client=client, response=response)) + + async def asyncio_detailed_getTagsEmployees(id: int, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetTagsEmployeesResponse200]] + """ + kwargs = _get_kwargs_getTagsEmployees(id=id, per=per, page=page) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getTagsEmployees(client=client, response=response) + + async def getTagsEmployees(id: int, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + return (await asyncio_detailed_getTagsEmployees(id=id, client=client, per=per, page=page)).parsed + + def _get_kwargs_post_tasks(*, body: PostTasksBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_post_tasks(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = PostTasksResponse400.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_post_tasks(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_post_tasks(client=client, response=response)) + + async def asyncio_detailed_post_tasks(*, client: Union[AuthenticatedClient, Client], body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PostTasksResponse201, PostTasksResponse400]] + """ + kwargs = _get_kwargs_post_tasks(body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_post_tasks(client=client, response=response) + + async def post_tasks(*, client: Union[AuthenticatedClient, Client], body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PostTasksResponse201, PostTasksResponse400] + """ + return (await asyncio_detailed_post_tasks(client=client, body=body)).parsed + + def _get_kwargs_postMessageReactions(id: str, *, body: PostMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_postMessageReactions(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postMessageReactions(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_postMessageReactions(client=client, response=response)) + + async def asyncio_detailed_postMessageReactions(id: str, *, client: Union[AuthenticatedClient, Client], body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + kwargs = _get_kwargs_postMessageReactions(id=id, body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_postMessageReactions(client=client, response=response) + + async def postMessageReactions(id: str, *, client: Union[AuthenticatedClient, Client], body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + return (await asyncio_detailed_postMessageReactions(id=id, client=client, body=body)).parsed + + def _get_kwargs_getMessageReactions(id: int, *, body: GetMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_getMessageReactions(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getMessageReactions(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getMessageReactions(client=client, response=response)) + + async def asyncio_detailed_getMessageReactions(id: int, *, client: Union[AuthenticatedClient, Client], body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + """ + kwargs = _get_kwargs_getMessageReactions(id=id, body=body) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getMessageReactions(client=client, response=response) + + async def getMessageReactions(id: int, *, client: Union[AuthenticatedClient, Client], body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + return (await asyncio_detailed_getMessageReactions(id=id, client=client, body=body)).parsed + + def _get_kwargs_deleteMessageReactions(id: str, *, code: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['code'] = code + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} + return _kwargs + + def _parse_response_deleteMessageReactions(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_deleteMessageReactions(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_deleteMessageReactions(client=client, response=response)) + + async def asyncio_detailed_deleteMessageReactions(id: str, *, client: Union[AuthenticatedClient, Client], code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + """ + kwargs = _get_kwargs_deleteMessageReactions(id=id, code=code) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_deleteMessageReactions(client=client, response=response) + + async def deleteMessageReactions(id: str, *, client: Union[AuthenticatedClient, Client], code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + return (await asyncio_detailed_deleteMessageReactions(id=id, client=client, code=code)).parsed + + def _get_kwargs_getEmployees(*, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params['query'] = query + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} + return _kwargs + + def _parse_response_getEmployees(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getEmployees(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[GetEmployeesResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getEmployees(client=client, response=response)) + + async def asyncio_detailed_getEmployees(*, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + kwargs = _get_kwargs_getEmployees(per=per, page=page, query=query) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getEmployees(client=client, response=response) + + async def getEmployees(*, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + return (await asyncio_detailed_getEmployees(client=client, per=per, page=page, query=query)).parsed + + def _get_kwargs_getEmployee(id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} + return _kwargs + + def _parse_response_getEmployee(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getEmployee(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=_parse_response_getEmployee(client=client, response=response)) + + async def asyncio_detailed_getEmployee(id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetEmployeeResponse200, NotFound]] + """ + kwargs = _get_kwargs_getEmployee(id=id) + response = await client.get_async_httpx_client().request(**kwargs) + return _build_response_getEmployee(client=client, response=response) + + async def getEmployee(id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + return (await asyncio_detailed_getEmployee(id=id, client=client)).parsed + + \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py new file mode 100644 index 0000000..5f92e76 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py @@ -0,0 +1,16 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py new file mode 100644 index 0000000..bf2d6c3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py @@ -0,0 +1,189 @@ +"""Contains all the data models used in inputs/outputs""" + +from .bad_request import BadRequest +from .base_employee import BaseEmployee +from .base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem +from .button import Button +from .chat import Chat +from .create_chat_body import CreateChatBody +from .create_chat_response_201 import CreateChatResponse201 +from .create_chat_response_400 import CreateChatResponse400 +from .create_chat_response_404 import CreateChatResponse404 +from .create_chat_response_422 import CreateChatResponse422 +from .create_message import CreateMessage +from .create_message_body import CreateMessageBody +from .create_message_entity_type import CreateMessageEntityType +from .create_message_files_item import CreateMessageFilesItem +from .create_message_files_item_file_type import CreateMessageFilesItemFileType +from .create_message_response_201 import CreateMessageResponse201 +from .create_thread_response_200 import CreateThreadResponse200 +from .create_thread_response_200_data import CreateThreadResponse200Data +from .delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from .delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem +from .delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, +) +from .delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem +from .delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, +) +from .direct_response import DirectResponse +from .edit_messages import EditMessages +from .edit_messages_buttons_item_item import EditMessagesButtonsItemItem +from .edit_messages_files import EditMessagesFiles +from .edit_messages_files_file_type import EditMessagesFilesFileType +from .employee import Employee +from .error import Error +from .error_payload import ErrorPayload +from .errors_code import ErrorsCode +from .errors_code_payload import ErrorsCodePayload +from .file_response import FileResponse +from .get_chat_response_200 import GetChatResponse200 +from .get_chat_response_404 import GetChatResponse404 +from .get_chats_availability import GetChatsAvailability +from .get_chats_response_200 import GetChatsResponse200 +from .get_chats_response_400 import GetChatsResponse400 +from .get_chats_response_404 import GetChatsResponse404 +from .get_chats_response_422 import GetChatsResponse422 +from .get_chats_sortid import GetChatsSortid +from .get_common_methods_response_200 import GetCommonMethodsResponse200 +from .get_employee_response_200 import GetEmployeeResponse200 +from .get_employees_response_200 import GetEmployeesResponse200 +from .get_list_message_response_200 import GetListMessageResponse200 +from .get_message_reactions_body import GetMessageReactionsBody +from .get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .get_message_response_200 import GetMessageResponse200 +from .get_status_response_200 import GetStatusResponse200 +from .get_tag_response_200 import GetTagResponse200 +from .get_tag_response_404 import GetTagResponse404 +from .get_tag_response_404_errors_item import GetTagResponse404ErrorsItem +from .get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload +from .get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .get_tags_response_200 import GetTagsResponse200 +from .get_tags_response_400 import GetTagsResponse400 +from .get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem +from .get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload +from .message import Message +from .message_entity_type import MessageEntityType +from .message_files_item import MessageFilesItem +from .message_files_item_file_type import MessageFilesItemFileType +from .message_forwarding import MessageForwarding +from .message_thread import MessageThread +from .not_found import NotFound +from .post_members_to_chats_body import PostMembersToChatsBody +from .post_message_reactions_body import PostMessageReactionsBody +from .post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .post_tags_to_chats_body import PostTagsToChatsBody +from .post_tasks_body import PostTasksBody +from .post_tasks_body_task import PostTasksBodyTask +from .post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem +from .post_tasks_response_201 import PostTasksResponse201 +from .post_tasks_response_201_data import PostTasksResponse201Data +from .post_tasks_response_201_data_custom_properties_item import PostTasksResponse201DataCustomPropertiesItem +from .post_tasks_response_400 import PostTasksResponse400 +from .put_messages_id_body import PutMessagesIdBody +from .put_messages_id_response_200 import PutMessagesIdResponse200 +from .put_status_response_201 import PutStatusResponse201 +from .query_chat import QueryChat +from .query_common_methods import QueryCommonMethods +from .query_status import QueryStatus +from .query_status_status import QueryStatusStatus +from .reaction import Reaction +from .status_type_0 import StatusType0 +from .tag import Tag + +__all__ = ( + "BadRequest", + "BaseEmployee", + "BaseEmployeeCustomPropertiesItem", + "Button", + "Chat", + "CreateChatBody", + "CreateChatResponse201", + "CreateChatResponse400", + "CreateChatResponse404", + "CreateChatResponse422", + "CreateMessage", + "CreateMessageBody", + "CreateMessageEntityType", + "CreateMessageFilesItem", + "CreateMessageFilesItemFileType", + "CreateMessageResponse201", + "CreateThreadResponse200", + "CreateThreadResponse200Data", + "DeleteMessageReactionsResponse400", + "DeleteMessageReactionsResponse400ErrorsItem", + "DeleteMessageReactionsResponse400ErrorsItemPayload", + "DeleteMessageReactionsResponse404", + "DeleteMessageReactionsResponse404ErrorsItem", + "DeleteMessageReactionsResponse404ErrorsItemPayload", + "DirectResponse", + "EditMessages", + "EditMessagesButtonsItemItem", + "EditMessagesFiles", + "EditMessagesFilesFileType", + "Employee", + "Error", + "ErrorPayload", + "ErrorsCode", + "ErrorsCodePayload", + "FileResponse", + "GetChatResponse200", + "GetChatResponse404", + "GetChatsAvailability", + "GetChatsResponse200", + "GetChatsResponse400", + "GetChatsResponse404", + "GetChatsResponse422", + "GetChatsSortid", + "GetCommonMethodsResponse200", + "GetEmployeeResponse200", + "GetEmployeesResponse200", + "GetListMessageResponse200", + "GetMessageReactionsBody", + "GetMessageReactionsResponse200", + "GetMessageResponse200", + "GetStatusResponse200", + "GetTagResponse200", + "GetTagResponse404", + "GetTagResponse404ErrorsItem", + "GetTagResponse404ErrorsItemPayload", + "GetTagsEmployeesResponse200", + "GetTagsResponse200", + "GetTagsResponse400", + "GetTagsResponse400ErrorsItem", + "GetTagsResponse400ErrorsItemPayload", + "Message", + "MessageEntityType", + "MessageFilesItem", + "MessageFilesItemFileType", + "MessageForwarding", + "MessageThread", + "NotFound", + "PostMembersToChatsBody", + "PostMessageReactionsBody", + "PostMessageReactionsResponse400", + "PostMessageReactionsResponse403", + "PostMessageReactionsResponse404", + "PostTagsToChatsBody", + "PostTasksBody", + "PostTasksBodyTask", + "PostTasksBodyTaskCustomPropertiesItem", + "PostTasksResponse201", + "PostTasksResponse201Data", + "PostTasksResponse201DataCustomPropertiesItem", + "PostTasksResponse400", + "PutMessagesIdBody", + "PutMessagesIdResponse200", + "PutStatusResponse201", + "QueryChat", + "QueryCommonMethods", + "QueryStatus", + "QueryStatusStatus", + "Reaction", + "StatusType0", + "Tag", +) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py new file mode 100644 index 0000000..17dd6ed --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BadRequest") + + +@_attrs_define +class BadRequest: + """ + Attributes: + error (Union[Unset, str]): + message (Union[Unset, str]): + """ + + error: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + message = d.pop("message", UNSET) + + bad_request = cls( + error=error, + message=message, + ) + + bad_request.additional_properties = d + return bad_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py new file mode 100644 index 0000000..b6a0314 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py @@ -0,0 +1,186 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + +T = TypeVar("T", bound="BaseEmployee") + + +@_attrs_define +class BaseEmployee: + """Базовый класс сотрудника. + + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + base_employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + ) + + base_employee.additional_properties = d + return base_employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py new file mode 100644 index 0000000..bee25c8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BaseEmployeeCustomPropertiesItem") + + +@_attrs_define +class BaseEmployeeCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + base_employee_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + base_employee_custom_properties_item.additional_properties = d + return base_employee_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py new file mode 100644 index 0000000..64ea323 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py @@ -0,0 +1,78 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Button") + + +@_attrs_define +class Button: + """ + Attributes: + text (str): + url (Union[Unset, str]): + data (Union[Unset, str]): + """ + + text: str + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + } + ) + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text") + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + button = cls( + text=text, + url=url, + data=data, + ) + + button.additional_properties = d + return button + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py new file mode 100644 index 0000000..7ef2560 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py @@ -0,0 +1,162 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Chat") + + +@_attrs_define +class Chat: + """Беседа или канал + + Attributes: + id (Union[Unset, int]): Идентификатор беседы или канала Example: 334. + name (Union[Unset, str]): Название Example: 🤿 aqua. + owner_id (Union[Unset, int]): Идентификатор пользователя, создавшего беседу или канал Example: 185. + created_at (Union[Unset, datetime.datetime]): Дата и время создания беседы или канала (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:56:53.000Z. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, участников Example: [185, 186, 187]. + group_tag_ids (Union[Unset, list[int]]): Массив идентификаторов тегов, участников + channel (Union[Unset, bool]): Тип: беседа (false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (false) или открытый (true) + last_message_at (Union[Unset, datetime.datetime]): Дата и время создания последнего сообщения в беседе/канале + (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:58:13.000Z. + meet_room_url (Union[Unset, str]): Ссылка на Видеочат Example: https://meet.pachca.com/aqua-94bb21b5. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + owner_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + member_ids: Union[Unset, list[int]] = UNSET + group_tag_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + last_message_at: Union[Unset, datetime.datetime] = UNSET + meet_room_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + owner_id = self.owner_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + group_tag_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.group_tag_ids, Unset): + group_tag_ids = self.group_tag_ids + + channel = self.channel + + public = self.public + + last_message_at: Union[Unset, str] = UNSET + if not isinstance(self.last_message_at, Unset): + last_message_at = self.last_message_at.isoformat() + + meet_room_url = self.meet_room_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if owner_id is not UNSET: + field_dict["owner_id"] = owner_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if group_tag_ids is not UNSET: + field_dict["group_tag_ids"] = group_tag_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + if last_message_at is not UNSET: + field_dict["last_message_at"] = last_message_at + if meet_room_url is not UNSET: + field_dict["meet_room_url"] = meet_room_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + owner_id = d.pop("owner_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + group_tag_ids = cast(list[int], d.pop("group_tag_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + _last_message_at = d.pop("last_message_at", UNSET) + last_message_at: Union[Unset, datetime.datetime] + if isinstance(_last_message_at, Unset): + last_message_at = UNSET + else: + last_message_at = isoparse(_last_message_at) + + meet_room_url = d.pop("meet_room_url", UNSET) + + chat = cls( + id=id, + name=name, + owner_id=owner_id, + created_at=created_at, + member_ids=member_ids, + group_tag_ids=group_tag_ids, + channel=channel, + public=public, + last_message_at=last_message_at, + meet_room_url=meet_room_url, + ) + + chat.additional_properties = d + return chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py new file mode 100644 index 0000000..8b9e361 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_chat import QueryChat + + +T = TypeVar("T", bound="CreateChatBody") + + +@_attrs_define +class CreateChatBody: + """ + Attributes: + chat (Union[Unset, QueryChat]): Собранный объект параметров создаваемой беседы или канала + """ + + chat: Union[Unset, "QueryChat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + chat: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.chat, Unset): + chat = self.chat.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if chat is not UNSET: + field_dict["chat"] = chat + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_chat import QueryChat + + d = src_dict.copy() + _chat = d.pop("chat", UNSET) + chat: Union[Unset, QueryChat] + if isinstance(_chat, Unset): + chat = UNSET + else: + chat = QueryChat.from_dict(_chat) + + create_chat_body = cls( + chat=chat, + ) + + create_chat_body.additional_properties = d + return create_chat_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py new file mode 100644 index 0000000..3a928ef --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="CreateChatResponse201") + + +@_attrs_define +class CreateChatResponse201: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + create_chat_response_201 = cls( + data=data, + ) + + create_chat_response_201.additional_properties = d + return create_chat_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py new file mode 100644 index 0000000..1d7fd30 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse400") + + +@_attrs_define +class CreateChatResponse400: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_400 = cls( + errors=errors, + ) + + create_chat_response_400.additional_properties = d + return create_chat_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py new file mode 100644 index 0000000..3de2654 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse404") + + +@_attrs_define +class CreateChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_404 = cls( + errors=errors, + ) + + create_chat_response_404.additional_properties = d + return create_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py new file mode 100644 index 0000000..c917758 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse422") + + +@_attrs_define +class CreateChatResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_422 = cls( + errors=errors, + ) + + create_chat_response_422.additional_properties = d + return create_chat_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py new file mode 100644 index 0000000..63e52de --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py @@ -0,0 +1,178 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_entity_type import CreateMessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + +T = TypeVar("T", bound="CreateMessage") + + +@_attrs_define +class CreateMessage: + """ + Attributes: + entity_id (int): + content (str): + entity_type (Union[Unset, CreateMessageEntityType]): Default: CreateMessageEntityType.DISCUSSION. + files (Union[Unset, list['CreateMessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + parent_message_id (Union[None, Unset, int]): + skip_invite_mentions (Union[Unset, bool]): Default: False. + link_preview (Union[Unset, bool]): Default: False. + """ + + entity_id: int + content: str + entity_type: Union[Unset, CreateMessageEntityType] = CreateMessageEntityType.DISCUSSION + files: Union[Unset, list["CreateMessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + skip_invite_mentions: Union[Unset, bool] = False + link_preview: Union[Unset, bool] = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + content = self.content + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + skip_invite_mentions = self.skip_invite_mentions + + link_preview = self.link_preview + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "content": content, + } + ) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + if skip_invite_mentions is not UNSET: + field_dict["skip_invite_mentions"] = skip_invite_mentions + if link_preview is not UNSET: + field_dict["link_preview"] = link_preview + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + d = src_dict.copy() + entity_id = d.pop("entity_id") + + content = d.pop("content") + + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, CreateMessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = CreateMessageEntityType(_entity_type) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = CreateMessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + skip_invite_mentions = d.pop("skip_invite_mentions", UNSET) + + link_preview = d.pop("link_preview", UNSET) + + create_message = cls( + entity_id=entity_id, + content=content, + entity_type=entity_type, + files=files, + buttons=buttons, + parent_message_id=parent_message_id, + skip_invite_mentions=skip_invite_mentions, + link_preview=link_preview, + ) + + create_message.additional_properties = d + return create_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py new file mode 100644 index 0000000..a8960fe --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_message import CreateMessage + + +T = TypeVar("T", bound="CreateMessageBody") + + +@_attrs_define +class CreateMessageBody: + """ + Attributes: + message (Union[Unset, CreateMessage]): + """ + + message: Union[Unset, "CreateMessage"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_message import CreateMessage + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, CreateMessage] + if isinstance(_message, Unset): + message = UNSET + else: + message = CreateMessage.from_dict(_message) + + create_message_body = cls( + message=message, + ) + + create_message_body.additional_properties = d + return create_message_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py new file mode 100644 index 0000000..067c6f4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class CreateMessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py new file mode 100644 index 0000000..a7c8ee3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py @@ -0,0 +1,84 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_files_item_file_type import CreateMessageFilesItemFileType + +T = TypeVar("T", bound="CreateMessageFilesItem") + + +@_attrs_define +class CreateMessageFilesItem: + """ + Attributes: + key (str): + name (str): + file_type (CreateMessageFilesItemFileType): + size (int): + """ + + key: str + name: str + file_type: CreateMessageFilesItemFileType + size: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "key": key, + "name": name, + "file_type": file_type, + "size": size, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key") + + name = d.pop("name") + + file_type = CreateMessageFilesItemFileType(d.pop("file_type")) + + size = d.pop("size") + + create_message_files_item = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + create_message_files_item.additional_properties = d + return create_message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py new file mode 100644 index 0000000..89889f9 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CreateMessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py new file mode 100644 index 0000000..b016d4c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="CreateMessageResponse201") + + +@_attrs_define +class CreateMessageResponse201: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + create_message_response_201 = cls( + data=data, + ) + + create_message_response_201.additional_properties = d + return create_message_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py new file mode 100644 index 0000000..15fd0b4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + +T = TypeVar("T", bound="CreateThreadResponse200") + + +@_attrs_define +class CreateThreadResponse200: + """ + Attributes: + data (Union[Unset, CreateThreadResponse200Data]): + """ + + data: Union[Unset, "CreateThreadResponse200Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, CreateThreadResponse200Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = CreateThreadResponse200Data.from_dict(_data) + + create_thread_response_200 = cls( + data=data, + ) + + create_thread_response_200.additional_properties = d + return create_thread_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py new file mode 100644 index 0000000..93b7457 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py @@ -0,0 +1,104 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateThreadResponse200Data") + + +@_attrs_define +class CreateThreadResponse200Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного треда. + chat_id (Union[Unset, int]): Идентификатор чата треда. + message_id (Union[Unset, int]): Идентификатор сообщения, к которому был создан тред. + message_chat_id (Union[Unset, int]): Идентификатор чата сообщения. + updated_at (Union[Unset, datetime.datetime]): Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + message_id: Union[Unset, int] = UNSET + message_chat_id: Union[Unset, int] = UNSET + updated_at: Union[Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + message_id = self.message_id + + message_chat_id = self.message_chat_id + + updated_at: Union[Unset, str] = UNSET + if not isinstance(self.updated_at, Unset): + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if message_id is not UNSET: + field_dict["message_id"] = message_id + if message_chat_id is not UNSET: + field_dict["message_chat_id"] = message_chat_id + if updated_at is not UNSET: + field_dict["updated_at"] = updated_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_id = d.pop("message_id", UNSET) + + message_chat_id = d.pop("message_chat_id", UNSET) + + _updated_at = d.pop("updated_at", UNSET) + updated_at: Union[Unset, datetime.datetime] + if isinstance(_updated_at, Unset): + updated_at = UNSET + else: + updated_at = isoparse(_updated_at) + + create_thread_response_200_data = cls( + id=id, + chat_id=chat_id, + message_id=message_id, + message_chat_id=message_chat_id, + updated_at=updated_at, + ) + + create_thread_response_200_data.additional_properties = d + return create_thread_response_200_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py new file mode 100644 index 0000000..100dc9c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400") + + +@_attrs_define +class DeleteMessageReactionsResponse400: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item import ( + DeleteMessageReactionsResponse400ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_400 = cls( + errors=errors, + ) + + delete_message_reactions_response_400.additional_properties = d + return delete_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py new file mode 100644 index 0000000..4a61277 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse400ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_400_errors_item.additional_properties = d + return delete_message_reactions_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py new file mode 100644 index 0000000..d3d26c9 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_400_errors_item_payload = cls() + + delete_message_reactions_response_400_errors_item_payload.additional_properties = d + return delete_message_reactions_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py new file mode 100644 index 0000000..9f918a0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404") + + +@_attrs_define +class DeleteMessageReactionsResponse404: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item import ( + DeleteMessageReactionsResponse404ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_404 = cls( + errors=errors, + ) + + delete_message_reactions_response_404.additional_properties = d + return delete_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py new file mode 100644 index 0000000..849db9d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse404ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_404_errors_item.additional_properties = d + return delete_message_reactions_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py new file mode 100644 index 0000000..f2fa5b5 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_404_errors_item_payload = cls() + + delete_message_reactions_response_404_errors_item_payload.additional_properties = d + return delete_message_reactions_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py new file mode 100644 index 0000000..aef4bc1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py @@ -0,0 +1,195 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DirectResponse") + + +@_attrs_define +class DirectResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + file (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + file: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + file = self.file + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + def to_multipart(self) -> dict[str, Any]: + content_disposition = ( + self.content_disposition + if isinstance(self.content_disposition, Unset) + else (None, str(self.content_disposition).encode(), "text/plain") + ) + + acl = self.acl if isinstance(self.acl, Unset) else (None, str(self.acl).encode(), "text/plain") + + policy = self.policy if isinstance(self.policy, Unset) else (None, str(self.policy).encode(), "text/plain") + + x_amz_credential = ( + self.x_amz_credential + if isinstance(self.x_amz_credential, Unset) + else (None, str(self.x_amz_credential).encode(), "text/plain") + ) + + x_amz_algorithm = ( + self.x_amz_algorithm + if isinstance(self.x_amz_algorithm, Unset) + else (None, str(self.x_amz_algorithm).encode(), "text/plain") + ) + + x_amz_date = ( + self.x_amz_date + if isinstance(self.x_amz_date, Unset) + else (None, str(self.x_amz_date).encode(), "text/plain") + ) + + x_amz_signature = ( + self.x_amz_signature + if isinstance(self.x_amz_signature, Unset) + else (None, str(self.x_amz_signature).encode(), "text/plain") + ) + + key = self.key if isinstance(self.key, Unset) else (None, str(self.key).encode(), "text/plain") + + file = self.file if isinstance(self.file, Unset) else (None, str(self.file).encode(), "text/plain") + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = (None, str(prop).encode(), "text/plain") + + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + file = d.pop("file", UNSET) + + direct_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + file=file, + ) + + direct_response.additional_properties = d + return direct_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py new file mode 100644 index 0000000..8e6439d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py @@ -0,0 +1,113 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + +T = TypeVar("T", bound="EditMessages") + + +@_attrs_define +class EditMessages: + """Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Attributes: + content (Union[Unset, str]): Текст сообщения Default: 'Текст сообщения'. + files (Union[Unset, EditMessagesFiles]): + buttons (Union[Unset, list[list['EditMessagesButtonsItemItem']]]): Массив строк, каждая из которых представлена + массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в + статье. Для удаления кнопок у сообщения пришлите пустой массив. + """ + + content: Union[Unset, str] = "Текст сообщения" + files: Union[Unset, "EditMessagesFiles"] = UNSET + buttons: Union[Unset, list[list["EditMessagesButtonsItemItem"]]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content = self.content + + files: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.files, Unset): + files = self.files.to_dict() + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for buttons_item_data in self.buttons: + buttons_item = [] + for buttons_item_item_data in buttons_item_data: + buttons_item_item = buttons_item_item_data.to_dict() + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content is not UNSET: + field_dict["content"] = content + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + d = src_dict.copy() + content = d.pop("content", UNSET) + + _files = d.pop("files", UNSET) + files: Union[Unset, EditMessagesFiles] + if isinstance(_files, Unset): + files = UNSET + else: + files = EditMessagesFiles.from_dict(_files) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for buttons_item_data in _buttons or []: + buttons_item = [] + _buttons_item = buttons_item_data + for buttons_item_item_data in _buttons_item: + buttons_item_item = EditMessagesButtonsItemItem.from_dict(buttons_item_item_data) + + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + edit_messages = cls( + content=content, + files=files, + buttons=buttons, + ) + + edit_messages.additional_properties = d + return edit_messages + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py new file mode 100644 index 0000000..22494f8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py @@ -0,0 +1,76 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesButtonsItemItem") + + +@_attrs_define +class EditMessagesButtonsItemItem: + """ + Attributes: + text (Union[Unset, str]): Текст, отображаемый на кнопке пользователю + url (Union[Unset, str]): Ссылка, которая будет открыта по нажатию кнопки + data (Union[Unset, str]): Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + """ + + text: Union[Unset, str] = UNSET + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if text is not UNSET: + field_dict["text"] = text + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text", UNSET) + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + edit_messages_buttons_item_item = cls( + text=text, + url=url, + data=data, + ) + + edit_messages_buttons_item_item.additional_properties = d + return edit_messages_buttons_item_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py new file mode 100644 index 0000000..f42b7bb --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py @@ -0,0 +1,95 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.edit_messages_files_file_type import EditMessagesFilesFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesFiles") + + +@_attrs_define +class EditMessagesFiles: + """ + Attributes: + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, EditMessagesFilesFileType]): + size (Union[Unset, int]): Размер файла в байтах, отображаемый пользователю Default: 1234. + """ + + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, EditMessagesFilesFileType] = UNSET + size: Union[Unset, int] = 1234 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if size is not UNSET: + field_dict["size"] = size + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, EditMessagesFilesFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = EditMessagesFilesFileType(_file_type) + + size = d.pop("size", UNSET) + + edit_messages_files = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + edit_messages_files.additional_properties = d + return edit_messages_files + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py new file mode 100644 index 0000000..a78a223 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class EditMessagesFilesFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py new file mode 100644 index 0000000..9011165 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py @@ -0,0 +1,275 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="Employee") + + +@_attrs_define +class Employee: + """ + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + user_status (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + title (Union[Unset, str]): Должность + created_at (Union[Unset, datetime.datetime]): Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone (Union[Unset, str]): Часовой пояс пользователя + image_url (Union[None, Unset, str]): Ссылка на скачивание аватарки + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + user_status: Union["StatusType0", None, Unset] = UNSET + title: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + time_zone: Union[Unset, str] = UNSET + image_url: Union[None, Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + user_status: Union[None, Unset, dict[str, Any]] + if isinstance(self.user_status, Unset): + user_status = UNSET + elif isinstance(self.user_status, StatusType0): + user_status = self.user_status.to_dict() + else: + user_status = self.user_status + + title = self.title + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + time_zone = self.time_zone + + image_url: Union[None, Unset, str] + if isinstance(self.image_url, Unset): + image_url = UNSET + else: + image_url = self.image_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + if user_status is not UNSET: + field_dict["user_status"] = user_status + if title is not UNSET: + field_dict["title"] = title + if created_at is not UNSET: + field_dict["created_at"] = created_at + if time_zone is not UNSET: + field_dict["time_zone"] = time_zone + if image_url is not UNSET: + field_dict["image_url"] = image_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + def _parse_user_status(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + user_status = _parse_user_status(d.pop("user_status", UNSET)) + + title = d.pop("title", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + time_zone = d.pop("time_zone", UNSET) + + def _parse_image_url(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + image_url = _parse_image_url(d.pop("image_url", UNSET)) + + employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + user_status=user_status, + title=title, + created_at=created_at, + time_zone=time_zone, + image_url=image_url, + ) + + employee.additional_properties = d + return employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py new file mode 100644 index 0000000..e9e73d2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error_payload import ErrorPayload + + +T = TypeVar("T", bound="Error") + + +@_attrs_define +class Error: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error_payload import ErrorPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorPayload.from_dict(_payload) + + error = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + error.additional_properties = d + return error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py new file mode 100644 index 0000000..9133249 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorPayload") + + +@_attrs_define +class ErrorPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error_payload = cls() + + error_payload.additional_properties = d + return error_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py new file mode 100644 index 0000000..52b0dee --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py @@ -0,0 +1,108 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code_payload import ErrorsCodePayload + + +T = TypeVar("T", bound="ErrorsCode") + + +@_attrs_define +class ErrorsCode: + """Bad Request + + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorsCodePayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorsCodePayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code_payload import ErrorsCodePayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorsCodePayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorsCodePayload.from_dict(_payload) + + errors_code = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + errors_code.additional_properties = d + return errors_code + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py new file mode 100644 index 0000000..8128de2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorsCodePayload") + + +@_attrs_define +class ErrorsCodePayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + errors_code_payload = cls() + + errors_code_payload.additional_properties = d + return errors_code_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py new file mode 100644 index 0000000..5bb1dc4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py @@ -0,0 +1,130 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FileResponse") + + +@_attrs_define +class FileResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + direct_url (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + direct_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + direct_url = self.direct_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if direct_url is not UNSET: + field_dict["direct_url"] = direct_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + direct_url = d.pop("direct_url", UNSET) + + file_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + direct_url=direct_url, + ) + + file_response.additional_properties = d + return file_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py new file mode 100644 index 0000000..274ed8c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatResponse200") + + +@_attrs_define +class GetChatResponse200: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + get_chat_response_200 = cls( + data=data, + ) + + get_chat_response_200.additional_properties = d + return get_chat_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py new file mode 100644 index 0000000..6aaf8b1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatResponse404") + + +@_attrs_define +class GetChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chat_response_404 = cls( + errors=errors, + ) + + get_chat_response_404.additional_properties = d + return get_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py new file mode 100644 index 0000000..b76cb4d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsAvailability(str, Enum): + IS_MEMBER = "is_member" + PUBLIC = "public" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py new file mode 100644 index 0000000..3917a9f --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatsResponse200") + + +@_attrs_define +class GetChatsResponse200: + """ + Attributes: + data (Union[Unset, list['Chat']]): + """ + + data: Union[Unset, list["Chat"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Chat.from_dict(data_item_data) + + data.append(data_item) + + get_chats_response_200 = cls( + data=data, + ) + + get_chats_response_200.additional_properties = d + return get_chats_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py new file mode 100644 index 0000000..005a6a3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code import ErrorsCode + + +T = TypeVar("T", bound="GetChatsResponse400") + + +@_attrs_define +class GetChatsResponse400: + """ + Attributes: + errors (Union[Unset, ErrorsCode]): Bad Request + """ + + errors: Union[Unset, "ErrorsCode"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.errors, Unset): + errors = self.errors.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code import ErrorsCode + + d = src_dict.copy() + _errors = d.pop("errors", UNSET) + errors: Union[Unset, ErrorsCode] + if isinstance(_errors, Unset): + errors = UNSET + else: + errors = ErrorsCode.from_dict(_errors) + + get_chats_response_400 = cls( + errors=errors, + ) + + get_chats_response_400.additional_properties = d + return get_chats_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py new file mode 100644 index 0000000..1553a65 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse404") + + +@_attrs_define +class GetChatsResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_404 = cls( + errors=errors, + ) + + get_chats_response_404.additional_properties = d + return get_chats_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py new file mode 100644 index 0000000..5248609 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse422") + + +@_attrs_define +class GetChatsResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_422 = cls( + errors=errors, + ) + + get_chats_response_422.additional_properties = d + return get_chats_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py new file mode 100644 index 0000000..0de410c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsSortid(str, Enum): + ASC = "asc" + DESC = "desc" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py new file mode 100644 index 0000000..93ea91d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_common_methods import QueryCommonMethods + + +T = TypeVar("T", bound="GetCommonMethodsResponse200") + + +@_attrs_define +class GetCommonMethodsResponse200: + """ + Attributes: + data (Union[Unset, list['QueryCommonMethods']]): + """ + + data: Union[Unset, list["QueryCommonMethods"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_common_methods import QueryCommonMethods + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = QueryCommonMethods.from_dict(data_item_data) + + data.append(data_item) + + get_common_methods_response_200 = cls( + data=data, + ) + + get_common_methods_response_200.additional_properties = d + return get_common_methods_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py new file mode 100644 index 0000000..b970ea8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeeResponse200") + + +@_attrs_define +class GetEmployeeResponse200: + """ + Attributes: + data (Union[Unset, Employee]): + """ + + data: Union[Unset, "Employee"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Employee] + if isinstance(_data, Unset): + data = UNSET + else: + data = Employee.from_dict(_data) + + get_employee_response_200 = cls( + data=data, + ) + + get_employee_response_200.additional_properties = d + return get_employee_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py new file mode 100644 index 0000000..978802c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeesResponse200") + + +@_attrs_define +class GetEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['Employee']]): + """ + + data: Union[Unset, list["Employee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Employee.from_dict(data_item_data) + + data.append(data_item) + + get_employees_response_200 = cls( + data=data, + ) + + get_employees_response_200.additional_properties = d + return get_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py new file mode 100644 index 0000000..52837e1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetListMessageResponse200") + + +@_attrs_define +class GetListMessageResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + get_list_message_response_200 = cls( + data=data, + ) + + get_list_message_response_200.additional_properties = d + return get_list_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py new file mode 100644 index 0000000..eaa7bb5 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py @@ -0,0 +1,68 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="GetMessageReactionsBody") + + +@_attrs_define +class GetMessageReactionsBody: + """ + Attributes: + per (Union[Unset, int]): Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). + Default: 50. + page (Union[Unset, int]): Номер страницы выборки (по умолчанию 1). Default: 1. + """ + + per: Union[Unset, int] = 50 + page: Union[Unset, int] = 1 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + per = self.per + + page = self.page + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if per is not UNSET: + field_dict["per"] = per + if page is not UNSET: + field_dict["page"] = page + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + per = d.pop("per", UNSET) + + page = d.pop("page", UNSET) + + get_message_reactions_body = cls( + per=per, + page=page, + ) + + get_message_reactions_body.additional_properties = d + return get_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py new file mode 100644 index 0000000..3c50c79 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.reaction import Reaction + + +T = TypeVar("T", bound="GetMessageReactionsResponse200") + + +@_attrs_define +class GetMessageReactionsResponse200: + """ + Attributes: + data (Union[Unset, list['Reaction']]): + """ + + data: Union[Unset, list["Reaction"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.reaction import Reaction + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Reaction.from_dict(data_item_data) + + data.append(data_item) + + get_message_reactions_response_200 = cls( + data=data, + ) + + get_message_reactions_response_200.additional_properties = d + return get_message_reactions_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py new file mode 100644 index 0000000..677295d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetMessageResponse200") + + +@_attrs_define +class GetMessageResponse200: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + get_message_response_200 = cls( + data=data, + ) + + get_message_response_200.additional_properties = d + return get_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py new file mode 100644 index 0000000..7e93886 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="GetStatusResponse200") + + +@_attrs_define +class GetStatusResponse200: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + get_status_response_200 = cls( + data=data, + ) + + get_status_response_200.additional_properties = d + return get_status_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py new file mode 100644 index 0000000..188f734 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagResponse200") + + +@_attrs_define +class GetTagResponse200: + """ + Attributes: + data (Union[Unset, Tag]): Для получения тега вам необходимо знать его id и указать его в URL запроса. + """ + + data: Union[Unset, "Tag"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Tag] + if isinstance(_data, Unset): + data = UNSET + else: + data = Tag.from_dict(_data) + + get_tag_response_200 = cls( + data=data, + ) + + get_tag_response_200.additional_properties = d + return get_tag_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py new file mode 100644 index 0000000..c3c8ead --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + +T = TypeVar("T", bound="GetTagResponse404") + + +@_attrs_define +class GetTagResponse404: + """ + Attributes: + errors (Union[Unset, list['GetTagResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["GetTagResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tag_response_404 = cls( + errors=errors, + ) + + get_tag_response_404.additional_properties = d + return get_tag_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py new file mode 100644 index 0000000..18649e6 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagResponse404ErrorsItem") + + +@_attrs_define +class GetTagResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, GetTagResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagResponse404ErrorsItemPayload.from_dict(_payload) + + get_tag_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tag_response_404_errors_item.additional_properties = d + return get_tag_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py new file mode 100644 index 0000000..b6d7c6c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagResponse404ErrorsItemPayload") + + +@_attrs_define +class GetTagResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tag_response_404_errors_item_payload = cls() + + get_tag_response_404_errors_item_payload.additional_properties = d + return get_tag_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py new file mode 100644 index 0000000..682b3fa --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee import BaseEmployee + + +T = TypeVar("T", bound="GetTagsEmployeesResponse200") + + +@_attrs_define +class GetTagsEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['BaseEmployee']]): + """ + + data: Union[Unset, list["BaseEmployee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee import BaseEmployee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = BaseEmployee.from_dict(data_item_data) + + data.append(data_item) + + get_tags_employees_response_200 = cls( + data=data, + ) + + get_tags_employees_response_200.additional_properties = d + return get_tags_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py new file mode 100644 index 0000000..1ae18d4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagsResponse200") + + +@_attrs_define +class GetTagsResponse200: + """ + Attributes: + data (Union[Unset, list['Tag']]): + """ + + data: Union[Unset, list["Tag"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Tag.from_dict(data_item_data) + + data.append(data_item) + + get_tags_response_200 = cls( + data=data, + ) + + get_tags_response_200.additional_properties = d + return get_tags_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py new file mode 100644 index 0000000..1865c60 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + +T = TypeVar("T", bound="GetTagsResponse400") + + +@_attrs_define +class GetTagsResponse400: + """ + Attributes: + errors (Union[Unset, list['GetTagsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["GetTagsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tags_response_400 = cls( + errors=errors, + ) + + get_tags_response_400.additional_properties = d + return get_tags_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py new file mode 100644 index 0000000..bd7859d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItem") + + +@_attrs_define +class GetTagsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, GetTagsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagsResponse400ErrorsItemPayload.from_dict(_payload) + + get_tags_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tags_response_400_errors_item.additional_properties = d + return get_tags_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py new file mode 100644 index 0000000..2e1d941 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItemPayload") + + +@_attrs_define +class GetTagsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tags_response_400_errors_item_payload = cls() + + get_tags_response_400_errors_item_payload.additional_properties = d + return get_tags_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py new file mode 100644 index 0000000..bb01030 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py @@ -0,0 +1,272 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..models.message_entity_type import MessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + +T = TypeVar("T", bound="Message") + + +@_attrs_define +class Message: + """ + Attributes: + entity_type (Union[Unset, MessageEntityType]): Default: MessageEntityType.DISCUSSION. + entity_id (Union[Unset, int]): + content (Union[Unset, str]): + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + user_id (Union[Unset, int]): + created_at (Union[Unset, datetime.datetime]): + files (Union[Unset, list['MessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + thread (Union['MessageThread', None, Unset]): + forwarding (Union['MessageForwarding', None, Unset]): + parent_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому написан ответ. Возвращается как + null, если сообщение не является ответом. + """ + + entity_type: Union[Unset, MessageEntityType] = MessageEntityType.DISCUSSION + entity_id: Union[Unset, int] = UNSET + content: Union[Unset, str] = UNSET + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + files: Union[Unset, list["MessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + thread: Union["MessageThread", None, Unset] = UNSET + forwarding: Union["MessageForwarding", None, Unset] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + entity_id = self.entity_id + + content = self.content + + id = self.id + + chat_id = self.chat_id + + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + thread: Union[None, Unset, dict[str, Any]] + if isinstance(self.thread, Unset): + thread = UNSET + elif isinstance(self.thread, MessageThread): + thread = self.thread.to_dict() + else: + thread = self.thread + + forwarding: Union[None, Unset, dict[str, Any]] + if isinstance(self.forwarding, Unset): + forwarding = UNSET + elif isinstance(self.forwarding, MessageForwarding): + forwarding = self.forwarding.to_dict() + else: + forwarding = self.forwarding + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if entity_id is not UNSET: + field_dict["entity_id"] = entity_id + if content is not UNSET: + field_dict["content"] = content + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if thread is not UNSET: + field_dict["thread"] = thread + if forwarding is not UNSET: + field_dict["forwarding"] = forwarding + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + d = src_dict.copy() + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, MessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = MessageEntityType(_entity_type) + + entity_id = d.pop("entity_id", UNSET) + + content = d.pop("content", UNSET) + + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = MessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_thread(data: object) -> Union["MessageThread", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + thread_type_0 = MessageThread.from_dict(data) + + return thread_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageThread", None, Unset], data) + + thread = _parse_thread(d.pop("thread", UNSET)) + + def _parse_forwarding(data: object) -> Union["MessageForwarding", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + forwarding_type_0 = MessageForwarding.from_dict(data) + + return forwarding_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageForwarding", None, Unset], data) + + forwarding = _parse_forwarding(d.pop("forwarding", UNSET)) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + message = cls( + entity_type=entity_type, + entity_id=entity_id, + content=content, + id=id, + chat_id=chat_id, + user_id=user_id, + created_at=created_at, + files=files, + buttons=buttons, + thread=thread, + forwarding=forwarding, + parent_message_id=parent_message_id, + ) + + message.additional_properties = d + return message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py new file mode 100644 index 0000000..e8a126a --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class MessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py new file mode 100644 index 0000000..21509d2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py @@ -0,0 +1,104 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.message_files_item_file_type import MessageFilesItemFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageFilesItem") + + +@_attrs_define +class MessageFilesItem: + """ + Attributes: + id (Union[Unset, int]): + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, MessageFilesItemFileType]): + url (Union[Unset, str]): Размер файла в байтах, отображаемый пользователю + """ + + id: Union[Unset, int] = UNSET + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, MessageFilesItemFileType] = UNSET + url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if url is not UNSET: + field_dict["url"] = url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, MessageFilesItemFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = MessageFilesItemFileType(_file_type) + + url = d.pop("url", UNSET) + + message_files_item = cls( + id=id, + key=key, + name=name, + file_type=file_type, + url=url, + ) + + message_files_item.additional_properties = d + return message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py new file mode 100644 index 0000000..1e00e5b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class MessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py new file mode 100644 index 0000000..6ce981d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py @@ -0,0 +1,153 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageForwarding") + + +@_attrs_define +class MessageForwarding: + """ + Attributes: + original_message_id (Union[Unset, int]): Идентификатор оригинального сообщения + original_chat_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + author_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + original_created_at (Union[Unset, int]): Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id (Union[None, Unset, int]): Идентификатор треда, в котором находится оригинальное сообщение. + Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому был создан тред, в + котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + original_thread_parent_chat_id (Union[None, Unset, int]): Идентификатор чата сообщения, к которому был создан + тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + """ + + original_message_id: Union[Unset, int] = UNSET + original_chat_id: Union[Unset, int] = UNSET + author_id: Union[Unset, int] = UNSET + original_created_at: Union[Unset, int] = UNSET + original_thread_id: Union[None, Unset, int] = UNSET + original_thread_message_id: Union[None, Unset, int] = UNSET + original_thread_parent_chat_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + original_message_id = self.original_message_id + + original_chat_id = self.original_chat_id + + author_id = self.author_id + + original_created_at = self.original_created_at + + original_thread_id: Union[None, Unset, int] + if isinstance(self.original_thread_id, Unset): + original_thread_id = UNSET + else: + original_thread_id = self.original_thread_id + + original_thread_message_id: Union[None, Unset, int] + if isinstance(self.original_thread_message_id, Unset): + original_thread_message_id = UNSET + else: + original_thread_message_id = self.original_thread_message_id + + original_thread_parent_chat_id: Union[None, Unset, int] + if isinstance(self.original_thread_parent_chat_id, Unset): + original_thread_parent_chat_id = UNSET + else: + original_thread_parent_chat_id = self.original_thread_parent_chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if original_message_id is not UNSET: + field_dict["original_message_id"] = original_message_id + if original_chat_id is not UNSET: + field_dict["original_chat_id"] = original_chat_id + if author_id is not UNSET: + field_dict["author_id"] = author_id + if original_created_at is not UNSET: + field_dict["original_created_at"] = original_created_at + if original_thread_id is not UNSET: + field_dict["original_thread_id"] = original_thread_id + if original_thread_message_id is not UNSET: + field_dict["original_thread_message_id"] = original_thread_message_id + if original_thread_parent_chat_id is not UNSET: + field_dict["original_thread_parent_chat_id"] = original_thread_parent_chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + original_message_id = d.pop("original_message_id", UNSET) + + original_chat_id = d.pop("original_chat_id", UNSET) + + author_id = d.pop("author_id", UNSET) + + original_created_at = d.pop("original_created_at", UNSET) + + def _parse_original_thread_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_id = _parse_original_thread_id(d.pop("original_thread_id", UNSET)) + + def _parse_original_thread_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_message_id = _parse_original_thread_message_id(d.pop("original_thread_message_id", UNSET)) + + def _parse_original_thread_parent_chat_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_parent_chat_id = _parse_original_thread_parent_chat_id( + d.pop("original_thread_parent_chat_id", UNSET) + ) + + message_forwarding = cls( + original_message_id=original_message_id, + original_chat_id=original_chat_id, + author_id=author_id, + original_created_at=original_created_at, + original_thread_id=original_thread_id, + original_thread_message_id=original_thread_message_id, + original_thread_parent_chat_id=original_thread_parent_chat_id, + ) + + message_forwarding.additional_properties = d + return message_forwarding + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py new file mode 100644 index 0000000..ddd18f0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageThread") + + +@_attrs_define +class MessageThread: + """ + Attributes: + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_thread = cls( + id=id, + chat_id=chat_id, + ) + + message_thread.additional_properties = d + return message_thread + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py new file mode 100644 index 0000000..c24e928 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py @@ -0,0 +1,59 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="NotFound") + + +@_attrs_define +class NotFound: + """Объект не найден + + Attributes: + detail (Union[Unset, str]): Описание ошибки Example: Страница не найдена.. + """ + + detail: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if detail is not UNSET: + field_dict["detail"] = detail + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + detail = d.pop("detail", UNSET) + + not_found = cls( + detail=detail, + ) + + not_found.additional_properties = d + return not_found + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py new file mode 100644 index 0000000..620f8dc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py @@ -0,0 +1,69 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMembersToChatsBody") + + +@_attrs_define +class PostMembersToChatsBody: + """ + Attributes: + member_ids (list[int]): Example: [186, 187]. + silent (Union[Unset, bool]): + """ + + member_ids: list[int] + silent: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + member_ids = self.member_ids + + silent = self.silent + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "member_ids": member_ids, + } + ) + if silent is not UNSET: + field_dict["silent"] = silent + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + member_ids = cast(list[int], d.pop("member_ids")) + + silent = d.pop("silent", UNSET) + + post_members_to_chats_body = cls( + member_ids=member_ids, + silent=silent, + ) + + post_members_to_chats_body.additional_properties = d + return post_members_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py new file mode 100644 index 0000000..fffa22a --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostMessageReactionsBody") + + +@_attrs_define +class PostMessageReactionsBody: + """ + Attributes: + code (str): Emoji в строковом формате для добавления реакции. + """ + + code: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "code": code, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + code = d.pop("code") + + post_message_reactions_body = cls( + code=code, + ) + + post_message_reactions_body.additional_properties = d + return post_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py new file mode 100644 index 0000000..50b0078 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse400") + + +@_attrs_define +class PostMessageReactionsResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_400 = cls( + error=error, + ) + + post_message_reactions_response_400.additional_properties = d + return post_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py new file mode 100644 index 0000000..cd52780 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse403") + + +@_attrs_define +class PostMessageReactionsResponse403: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_403 = cls( + error=error, + ) + + post_message_reactions_response_403.additional_properties = d + return post_message_reactions_response_403 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py new file mode 100644 index 0000000..1a26c89 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse404") + + +@_attrs_define +class PostMessageReactionsResponse404: + """ + Attributes: + error (Union[Unset, str]): Сообщение не найдено. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_404 = cls( + error=error, + ) + + post_message_reactions_response_404.additional_properties = d + return post_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py new file mode 100644 index 0000000..23040f4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostTagsToChatsBody") + + +@_attrs_define +class PostTagsToChatsBody: + """ + Attributes: + group_tag_ids (list[int]): Example: [86, 18]. + """ + + group_tag_ids: list[int] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + group_tag_ids = self.group_tag_ids + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "group_tag_ids": group_tag_ids, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + group_tag_ids = cast(list[int], d.pop("group_tag_ids")) + + post_tags_to_chats_body = cls( + group_tag_ids=group_tag_ids, + ) + + post_tags_to_chats_body.additional_properties = d + return post_tags_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py new file mode 100644 index 0000000..1abee57 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_body_task import PostTasksBodyTask + + +T = TypeVar("T", bound="PostTasksBody") + + +@_attrs_define +class PostTasksBody: + """ + Attributes: + task (Union[Unset, PostTasksBodyTask]): + """ + + task: Union[Unset, "PostTasksBodyTask"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + task: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.task, Unset): + task = self.task.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if task is not UNSET: + field_dict["task"] = task + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_body_task import PostTasksBodyTask + + d = src_dict.copy() + _task = d.pop("task", UNSET) + task: Union[Unset, PostTasksBodyTask] + if isinstance(_task, Unset): + task = UNSET + else: + task = PostTasksBodyTask.from_dict(_task) + + post_tasks_body = cls( + task=task, + ) + + post_tasks_body.additional_properties = d + return post_tasks_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py new file mode 100644 index 0000000..f85bf85 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py @@ -0,0 +1,123 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem + + +T = TypeVar("T", bound="PostTasksBodyTask") + + +@_attrs_define +class PostTasksBodyTask: + """ + Attributes: + kind (str): Тип напоминания (call, meeting, reminder, event, email) + content (str): Описание напоминания + due_at (datetime.datetime): Срок выполнения напоминания (ISO-8601) + priority (Union[Unset, int]): Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей + custom_properties (Union[Unset, list['PostTasksBodyTaskCustomPropertiesItem']]): + """ + + kind: str + content: str + due_at: datetime.datetime + priority: Union[Unset, int] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["PostTasksBodyTaskCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind = self.kind + + content = self.content + + due_at = self.due_at.isoformat() + + priority = self.priority + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "content": content, + "due_at": due_at, + } + ) + if priority is not UNSET: + field_dict["priority"] = priority + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem + + d = src_dict.copy() + kind = d.pop("kind") + + content = d.pop("content") + + due_at = isoparse(d.pop("due_at")) + + priority = d.pop("priority", UNSET) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = PostTasksBodyTaskCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + post_tasks_body_task = cls( + kind=kind, + content=content, + due_at=due_at, + priority=priority, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + post_tasks_body_task.additional_properties = d + return post_tasks_body_task + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py new file mode 100644 index 0000000..279e511 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksBodyTaskCustomPropertiesItem") + + +@_attrs_define +class PostTasksBodyTaskCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + value (Union[Unset, str]): Значение поля + """ + + id: Union[Unset, int] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + value = d.pop("value", UNSET) + + post_tasks_body_task_custom_properties_item = cls( + id=id, + value=value, + ) + + post_tasks_body_task_custom_properties_item.additional_properties = d + return post_tasks_body_task_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py new file mode 100644 index 0000000..5dcd6b7 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_response_201_data import PostTasksResponse201Data + + +T = TypeVar("T", bound="PostTasksResponse201") + + +@_attrs_define +class PostTasksResponse201: + """ + Attributes: + data (Union[Unset, PostTasksResponse201Data]): + """ + + data: Union[Unset, "PostTasksResponse201Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_response_201_data import PostTasksResponse201Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, PostTasksResponse201Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = PostTasksResponse201Data.from_dict(_data) + + post_tasks_response_201 = cls( + data=data, + ) + + post_tasks_response_201.additional_properties = d + return post_tasks_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py new file mode 100644 index 0000000..b714c69 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py @@ -0,0 +1,177 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_response_201_data_custom_properties_item import ( + PostTasksResponse201DataCustomPropertiesItem, + ) + + +T = TypeVar("T", bound="PostTasksResponse201Data") + + +@_attrs_define +class PostTasksResponse201Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного напоминания + kind (Union[Unset, str]): Тип + content (Union[Unset, str]): Описание + due_at (Union[Unset, datetime.datetime]): Срок выполнения (ISO-8601) + priority (Union[Unset, int]): Приоритет + user_id (Union[Unset, int]): Идентификатор пользователя-создателя + status (Union[Unset, str]): Статус напоминания + created_at (Union[Unset, datetime.datetime]): Дата и время создания + performer_ids (Union[Unset, list[int]]): + custom_properties (Union[Unset, list['PostTasksResponse201DataCustomPropertiesItem']]): + """ + + id: Union[Unset, int] = UNSET + kind: Union[Unset, str] = UNSET + content: Union[Unset, str] = UNSET + due_at: Union[Unset, datetime.datetime] = UNSET + priority: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + status: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["PostTasksResponse201DataCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + kind = self.kind + + content = self.content + + due_at: Union[Unset, str] = UNSET + if not isinstance(self.due_at, Unset): + due_at = self.due_at.isoformat() + + priority = self.priority + + user_id = self.user_id + + status = self.status + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if kind is not UNSET: + field_dict["kind"] = kind + if content is not UNSET: + field_dict["content"] = content + if due_at is not UNSET: + field_dict["due_at"] = due_at + if priority is not UNSET: + field_dict["priority"] = priority + if user_id is not UNSET: + field_dict["user_id"] = user_id + if status is not UNSET: + field_dict["status"] = status + if created_at is not UNSET: + field_dict["created_at"] = created_at + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_response_201_data_custom_properties_item import ( + PostTasksResponse201DataCustomPropertiesItem, + ) + + d = src_dict.copy() + id = d.pop("id", UNSET) + + kind = d.pop("kind", UNSET) + + content = d.pop("content", UNSET) + + _due_at = d.pop("due_at", UNSET) + due_at: Union[Unset, datetime.datetime] + if isinstance(_due_at, Unset): + due_at = UNSET + else: + due_at = isoparse(_due_at) + + priority = d.pop("priority", UNSET) + + user_id = d.pop("user_id", UNSET) + + status = d.pop("status", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = PostTasksResponse201DataCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + post_tasks_response_201_data = cls( + id=id, + kind=kind, + content=content, + due_at=due_at, + priority=priority, + user_id=user_id, + status=status, + created_at=created_at, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + post_tasks_response_201_data.additional_properties = d + return post_tasks_response_201_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py new file mode 100644 index 0000000..1dc217e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksResponse201DataCustomPropertiesItem") + + +@_attrs_define +class PostTasksResponse201DataCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + post_tasks_response_201_data_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + post_tasks_response_201_data_custom_properties_item.additional_properties = d + return post_tasks_response_201_data_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py new file mode 100644 index 0000000..e5ca651 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksResponse400") + + +@_attrs_define +class PostTasksResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_tasks_response_400 = cls( + error=error, + ) + + post_tasks_response_400.additional_properties = d + return post_tasks_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py new file mode 100644 index 0000000..24a5140 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py @@ -0,0 +1,72 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages import EditMessages + + +T = TypeVar("T", bound="PutMessagesIdBody") + + +@_attrs_define +class PutMessagesIdBody: + """ + Attributes: + message (Union[Unset, EditMessages]): Для получения сообщения вам необходимо знать его id и указать его в URL + запроса. + """ + + message: Union[Unset, "EditMessages"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages import EditMessages + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, EditMessages] + if isinstance(_message, Unset): + message = UNSET + else: + message = EditMessages.from_dict(_message) + + put_messages_id_body = cls( + message=message, + ) + + put_messages_id_body.additional_properties = d + return put_messages_id_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py new file mode 100644 index 0000000..5cb478f --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="PutMessagesIdResponse200") + + +@_attrs_define +class PutMessagesIdResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): Созданное сообщение + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + put_messages_id_response_200 = cls( + data=data, + ) + + put_messages_id_response_200.additional_properties = d + return put_messages_id_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py new file mode 100644 index 0000000..a34d4e0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="PutStatusResponse201") + + +@_attrs_define +class PutStatusResponse201: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + put_status_response_201 = cls( + data=data, + ) + + put_status_response_201.additional_properties = d + return put_status_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py new file mode 100644 index 0000000..f3e1788 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py @@ -0,0 +1,91 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryChat") + + +@_attrs_define +class QueryChat: + """Собранный объект параметров создаваемой беседы или канала + + Attributes: + name (str): Название Example: 🤿 aqua. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, которые станут участниками Example: + [186, 187]. + channel (Union[Unset, bool]): Тип: беседа (по умолчанию, false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (по умолчанию, false) или открытый (true) + """ + + name: str + member_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + channel = self.channel + + public = self.public + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + query_chat = cls( + name=name, + member_ids=member_ids, + channel=channel, + public=public, + ) + + query_chat.additional_properties = d + return query_chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py new file mode 100644 index 0000000..f575b43 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryCommonMethods") + + +@_attrs_define +class QueryCommonMethods: + """получение списка актульных полей сущности. + + Attributes: + id (Union[Unset, int]): Название поля Example: 1. + name (Union[Unset, str]): Идентификатор поля Example: Дата рождения. + data_type (Union[Unset, str]): тип поля (string, number, date или link) Example: number. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + query_common_methods = cls( + id=id, + name=name, + data_type=data_type, + ) + + query_common_methods.additional_properties = d + return query_common_methods + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py new file mode 100644 index 0000000..885c9fc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_status_status import QueryStatusStatus + + +T = TypeVar("T", bound="QueryStatus") + + +@_attrs_define +class QueryStatus: + """ + Attributes: + status (Union[Unset, QueryStatusStatus]): Собранный объект параметров нового статуса + """ + + status: Union[Unset, "QueryStatusStatus"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.status, Unset): + status = self.status.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if status is not UNSET: + field_dict["status"] = status + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_status_status import QueryStatusStatus + + d = src_dict.copy() + _status = d.pop("status", UNSET) + status: Union[Unset, QueryStatusStatus] + if isinstance(_status, Unset): + status = UNSET + else: + status = QueryStatusStatus.from_dict(_status) + + query_status = cls( + status=status, + ) + + query_status.additional_properties = d + return query_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py new file mode 100644 index 0000000..48858ea --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py @@ -0,0 +1,102 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryStatusStatus") + + +@_attrs_define +class QueryStatusStatus: + """Собранный объект параметров нового статуса + + Attributes: + emoji (str): Emoji символ статуса + title (str): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ + """ + + emoji: str + title: str + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "emoji": emoji, + "title": title, + } + ) + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji") + + title = d.pop("title") + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + query_status_status = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + query_status_status.additional_properties = d + return query_status_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py new file mode 100644 index 0000000..de28f69 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py @@ -0,0 +1,86 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Reaction") + + +@_attrs_define +class Reaction: + """ + Attributes: + user_id (Union[Unset, int]): Идентификатор пользователя, оставившего реакцию. + created_at (Union[Unset, datetime.datetime]): Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY- + MM-DDThh:mm:ss.sssZ. + code (Union[Unset, str]): Emoji символ реакции. + """ + + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + code: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if code is not UNSET: + field_dict["code"] = code + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + code = d.pop("code", UNSET) + + reaction = cls( + user_id=user_id, + created_at=created_at, + code=code, + ) + + reaction.additional_properties = d + return reaction + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py new file mode 100644 index 0000000..8997cfe --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py @@ -0,0 +1,101 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="StatusType0") + + +@_attrs_define +class StatusType0: + """Статус. Возвращается как null, если статус не установлен. + + Attributes: + emoji (Union[Unset, str]): Emoji символ статуса + title (Union[Unset, str]): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + """ + + emoji: Union[Unset, str] = UNSET + title: Union[Unset, str] = UNSET + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if emoji is not UNSET: + field_dict["emoji"] = emoji + if title is not UNSET: + field_dict["title"] = title + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji", UNSET) + + title = d.pop("title", UNSET) + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + status_type_0 = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + status_type_0.additional_properties = d + return status_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py new file mode 100644 index 0000000..6504540 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Tag") + + +@_attrs_define +class Tag: + """Для получения тега вам необходимо знать его id и указать его в URL запроса. + + Attributes: + id (Union[Unset, int]): Идентификатор тега + name (Union[Unset, str]): Название тега + users_count (Union[Unset, int]): Количество сотрудников, которые имеют этот тег + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + users_count: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + users_count = self.users_count + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if users_count is not UNSET: + field_dict["users_count"] = users_count + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + users_count = d.pop("users_count", UNSET) + + tag = cls( + id=id, + name=name, + users_count=users_count, + ) + + tag.additional_properties = d + return tag + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed new file mode 100644 index 0000000..1aad327 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py new file mode 100644 index 0000000..b9ed58b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py @@ -0,0 +1,46 @@ +"""Contains some shared types for properties""" + +from collections.abc import MutableMapping +from http import HTTPStatus +from typing import BinaryIO, Generic, Literal, Optional, TypeVar + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: Optional[str] = None + mime_type: Optional[str] = None + + def to_tuple(self) -> FileJsonType: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: Optional[T] + + +__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/pachca-api-open-api-3-0-client/pyproject.toml b/pachca-api-open-api-3-0-client/pyproject.toml new file mode 100644 index 0000000..29f8de8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pyproject.toml @@ -0,0 +1,27 @@ +[tool.poetry] +name = "pachca-api-open-api-3-0-client" +version = "3.0.3" +description = "A client library for accessing PachcaAPI - OpenAPI 3.0" +authors = [] +readme = "README.md" +packages = [ + {include = "pachca_api_open_api_3_0_client"}, +] +include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] + + +[tool.poetry.dependencies] +python = "^3.9" +httpx = ">=0.20.0,<0.28.0" +attrs = ">=21.3.0" +python-dateutil = "^2.8.0" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["F", "I", "UP"] diff --git a/pachca.py b/pachca.py new file mode 100644 index 0000000..4f882fe --- /dev/null +++ b/pachca.py @@ -0,0 +1,34 @@ +import asyncio + +from pachca_api_open_api_3_0_client import AuthenticatedClient +from pachca_api_open_api_3_0_client.api.chats_and_channels.create_chat import ( + asyncio as as2, +) +from pachca_api_open_api_3_0_client.api.employees.get_employees import ( + asyncio as as1, +) +from pachca_api_open_api_3_0_client.models.create_chat_body import ( + CreateChatBody, +) +from pachca_api_open_api_3_0_client.models.query_chat import QueryChat + +client = AuthenticatedClient( + base_url='https://api.pachca.com/api/shared/v1', + token='35KekGygDNiFwtPpqUe44CaEZ_EVL17ycYRJrMnvHOs', +) + +query_chat = QueryChat(name='test') +chat_body = CreateChatBody(chat=query_chat) + + +async def main(): + task1 = asyncio.create_task(as1(client=client)) + task2 = asyncio.create_task(as2(client=client, body=chat_body)) + + print(await task1) + print('*' * 30) + print(await task2) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/script.py b/script.py new file mode 100644 index 0000000..7202544 --- /dev/null +++ b/script.py @@ -0,0 +1,40 @@ +import ast +import os + +from jinja2 import Environment, FileSystemLoader + + +def extract_functions_from_file(file_path): + with open(file_path, "r", encoding="utf-8") as file: + tree = ast.parse(file.read()) + + functions = [] + for node in ast.walk(tree): + if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, ast.FunctionDef): + functions.append(ast.unparse(node)) + return functions + +def get_all_api_functions(api_dir): + all_functions = [] + for root, _, files in os.walk(api_dir): + for file in files: + if file.endswith(".py"): + file_path = os.path.join(root, file) + functions = extract_functions_from_file(file_path) + all_functions.extend(functions) + return all_functions + + +api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" +endpoints = get_all_api_functions(api_dir) + +env = Environment( + loader=FileSystemLoader('templates') +) + +client_template = env.get_template('client.py.jinja') + +client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' + +with open(client_path, mode='w') as file: + file.write(client_template.render(endpoints=endpoints)) diff --git a/templates/client.py.jinja b/templates/client.py.jinja new file mode 100644 index 0000000..3a44e77 --- /dev/null +++ b/templates/client.py.jinja @@ -0,0 +1,133 @@ +import ssl +from typing import Any, Union, Optional + +from attrs import define, field, evolve +import httpx + +{% from "macros/client_macros.py.jinja" import httpx_args_docstring %} + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + {{ httpx_args_docstring() }} + + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class Pachca: + """Главный класс библиотеки.""" + + def __init__(self, base_url, token): + self.client = AuthenticatedClient(base_url=base_url, token=token) + + {% if endpoints %} + {% for endpoint in endpoints %} + {{ endpoint | indent(4, first=Fasle) }} + {% endfor %} + {% endif %} \ No newline at end of file diff --git a/templates/endpoint_module.py.jinja b/templates/endpoint_module.py.jinja new file mode 100644 index 0000000..016f816 --- /dev/null +++ b/templates/endpoint_module.py.jinja @@ -0,0 +1,125 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ...client import AuthenticatedClient, Client +from ...types import Response, UNSET +from ... import errors + +{% for relative in endpoint.relative_imports | sort %} +{{ relative }} +{% endfor %} + +{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, + arguments, client, kwargs, parse_response, docstring, body_to_kwarg %} + +{% set return_string = endpoint.response_type() %} +{% set parsed_responses = (endpoint.responses | length > 0) and return_string != "Any" %} + +def _get_kwargs_{{ endpoint.name }}( + {{ arguments(endpoint, include_client=False) | indent(4) }} +) -> dict[str, Any]: + {{ header_params(endpoint) | indent(4) }} + + {{ cookie_params(endpoint) | indent(4) }} + + {{ query_params(endpoint) | indent(4) }} + + _kwargs: dict[str, Any] = { + "method": "{{ endpoint.method }}", + {% if endpoint.path_parameters %} + "url": "{{ endpoint.path }}".format( + {%- for parameter in endpoint.path_parameters -%} + {{parameter.python_name}}={{parameter.python_name}}, + {%- endfor -%} + ), + {% else %} + "url": "{{ endpoint.path }}", + {% endif %} + {% if endpoint.query_parameters %} + "params": params, + {% endif %} + {% if endpoint.cookie_parameters %} + "cookies": cookies, + {% endif %} + } + +{% if endpoint.bodies | length > 1 %} +{% for body in endpoint.bodies %} + if isinstance(body, {{body.prop.get_type_string() }}): + {% set destination = "_" + body.body_type + "_body" %} + {{ body_to_kwarg(body, destination) | indent(8) }} + _kwargs["{{ body.body_type.value }}"] = {{ destination }} + headers["Content-Type"] = "{{ body.content_type }}" +{% endfor %} +{% elif endpoint.bodies | length == 1 %} +{% set body = endpoint.bodies[0] %} + {{ body_to_kwarg(body, "_body") | indent(4) }} + _kwargs["{{ body.body_type.value }}"] = _body + {% if body.content_type != "multipart/form-data" %}{# Need httpx to set the boundary automatically #} + headers["Content-Type"] = "{{ body.content_type }}" + {% endif %} +{% endif %} + +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} + _kwargs["headers"] = headers +{% endif %} + return _kwargs + + +def _parse_response_{{ endpoint.name }}(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[{{ return_string }}]: + {% for response in endpoint.responses %} + if response.status_code == {{ response.status_code.value }}: + {% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %} + {% if prop_template.construct %} + {{ prop_template.construct(response.prop, response.source.attribute) | indent(8) }} + {% elif response.source.return_type == response.prop.get_type_string() %} + {{ response.prop.python_name }} = {{ response.source.attribute }} + {% else %} + {{ response.prop.python_name }} = cast({{ response.prop.get_type_string() }}, {{ response.source.attribute }}) + {% endif %} + return {{ response.prop.python_name }} + {% else %} + return None + {% endif %} + {% endfor %} + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_{{ endpoint.name }}(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[{{ return_string }}]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response_{{ endpoint.name }}(client=client, response=response), + ) + +async def asyncio_detailed_{{ endpoint.name }}( + {{ arguments(endpoint) | indent(4) }} +) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = _get_kwargs_{{ endpoint.name }}( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = await client.get_async_httpx_client().request( + **kwargs + ) + + return _build_response_{{ endpoint.name }}(client=client, response=response) + +{% if parsed_responses %} +async def {{ endpoint.name }}( + {{ arguments(endpoint) | indent(4) }} +) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return (await asyncio_detailed_{{ endpoint.name }}( + {{ kwargs(endpoint) }} + )).parsed +{% endif %} diff --git a/templates/macros/client_macros.py.jinja b/templates/macros/client_macros.py.jinja new file mode 100644 index 0000000..35f0b76 --- /dev/null +++ b/templates/macros/client_macros.py.jinja @@ -0,0 +1,25 @@ +{% macro httpx_args_docstring() %} + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + ``token``: The token to use for authentication + + ``prefix``: The prefix to use for the Authorization header + + ``auth_header_name``: The name of the Authorization header +{% endmacro %} \ No newline at end of file From d54a453aa47591ddf758040aa9d200635baff7cf Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Tue, 24 Dec 2024 11:22:27 +0300 Subject: [PATCH 074/296] added missing opIds, fixed double spaces near descriptions --- openapi.yaml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 7a6d84a..261e4e0 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -130,7 +130,7 @@ paths: maximum: 50 - name: page in: query - description: Страница выборки (по умолчанию 1) + description: Страница выборки (по умолчанию 1) required: false schema: type: integer @@ -420,7 +420,7 @@ paths: maximum: 50 - name: page in: query - description: Страница выборки (по умолчанию 1) + description: Страница выборки (по умолчанию 1) required: false schema: type: integer @@ -438,7 +438,7 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Поле имеет недопустимое значение content: application/json: schema: @@ -829,6 +829,7 @@ paths: delete: tags: - talk and channel participants + operationId: leaveChat summary: 'Выход из беседы или канала' description: |- Метод для самостоятельного выхода из беседы или канала. @@ -1198,7 +1199,8 @@ paths: code: not_found put: tags: - - messages + - message + operationId: editMessage summary: Редактирование сообщения description: Метод для редактирования сообщения или комментария. parameters: @@ -1504,6 +1506,7 @@ paths: post: tags: - reminders + operationId: createTask summary: 'Метод для создания нового напоминания.' description: | При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. @@ -1758,11 +1761,11 @@ components: Status: type: object nullable: true - description: Статус. Возвращается как null, если статус не установлен. + description: Статус. Возвращается как null, если статус не установлен. properties: emoji: type: string - description: Emoji символ статуса + description: Emoji символ статуса title: type: string description: Текст статуса @@ -1795,7 +1798,7 @@ components: nullable: true QueryCommonMethods: type: object - description: получение списка актульных полей сущности. + description: получение списка актульных полей сущности. properties: id: type: integer From e58ac6f432df76e9e78d080e1df9194595ed7d53 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Tue, 24 Dec 2024 11:51:42 +0300 Subject: [PATCH 075/296] removed double spaces in line 140 --- openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 261e4e0..0c2a4f4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -138,7 +138,7 @@ paths: - name: query in: query description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) required: false schema: type: string From 55f48a06404bb3e69967260ad5cdad991d474860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 24 Dec 2024 16:29:12 +0300 Subject: [PATCH 076/296] add file pachca --- pachca-api-open-api-3-0-client/.gitignore | 23 + pachca-api-open-api-3-0-client/README.md | 124 +++++ .../__init__.py | 8 + .../api/__init__.py | 1 + .../api/chats_and_channels/__init__.py | 0 .../api/chats_and_channels/create_chat.py | 187 +++++++ .../api/chats_and_channels/get_chat.py | 167 ++++++ .../api/chats_and_channels/get_chats.py | 277 +++++++++ .../api/comments/__init__.py | 0 .../api/comments/create_thread.py | 172 ++++++ .../api/common_methods/__init__.py | 0 .../api/common_methods/get_common_methods.py | 175 ++++++ .../api/common_methods/get_direct_url.py | 106 ++++ .../api/common_methods/get_uploads.py | 130 +++++ .../api/employees/__init__.py | 0 .../api/employees/get_employee.py | 167 ++++++ .../api/employees/get_employees.py | 196 +++++++ .../api/messages/__init__.py | 0 .../api/messages/create_message.py | 231 ++++++++ .../api/messages/get_list_message.py | 226 ++++++++ .../api/messages/get_message.py | 171 ++++++ .../api/messages/put_messages_id.py | 200 +++++++ .../api/reactions_to_messages/__init__.py | 0 .../delete_message_reactions.py | 191 +++++++ .../get_message_reactions.py | 195 +++++++ .../post_message_reactions.py | 214 +++++++ .../api/reminders/__init__.py | 0 .../api/reminders/post_tasks.py | 193 +++++++ .../api/status/__init__.py | 0 .../api/status/del_status.py | 83 +++ .../api/status/get_status.py | 134 +++++ .../api/status/put_status.py | 173 ++++++ .../api/tags/__init__.py | 0 .../api/tags/get_tag.py | 163 ++++++ .../api/tags/get_tags.py | 186 +++++++ .../api/tags/get_tags_employees.py | 199 +++++++ .../talk_and_channel_participants/__init__.py | 0 .../delete_chats_id_leave.py | 175 ++++++ .../post_members_to_chats.py | 189 +++++++ .../post_tags_to_chats.py | 189 +++++++ .../pachca_api_open_api_3_0_client/client.py | 274 +++++++++ .../pachca_api_open_api_3_0_client/errors.py | 16 + .../models/__init__.py | 189 +++++++ .../models/bad_request.py | 67 +++ .../models/base_employee.py | 186 +++++++ .../base_employee_custom_properties_item.py | 85 +++ .../models/button.py | 78 +++ .../models/chat.py | 162 ++++++ .../models/create_chat_body.py | 71 +++ .../models/create_chat_response_201.py | 71 +++ .../models/create_chat_response_400.py | 74 +++ .../models/create_chat_response_404.py | 74 +++ .../models/create_chat_response_422.py | 74 +++ .../models/create_message.py | 178 ++++++ .../models/create_message_body.py | 71 +++ .../models/create_message_entity_type.py | 10 + .../models/create_message_files_item.py | 84 +++ .../create_message_files_item_file_type.py | 9 + .../models/create_message_response_201.py | 71 +++ .../models/create_thread_response_200.py | 71 +++ .../models/create_thread_response_200_data.py | 104 ++++ .../delete_message_reactions_response_400.py | 76 +++ ...sage_reactions_response_400_errors_item.py | 111 ++++ ...ctions_response_400_errors_item_payload.py | 43 ++ .../delete_message_reactions_response_404.py | 76 +++ ...sage_reactions_response_404_errors_item.py | 111 ++++ ...ctions_response_404_errors_item_payload.py | 43 ++ .../models/direct_response.py | 195 +++++++ .../models/edit_messages.py | 113 ++++ .../models/edit_messages_buttons_item_item.py | 76 +++ .../models/edit_messages_files.py | 95 ++++ .../models/edit_messages_files_file_type.py | 9 + .../models/employee.py | 275 +++++++++ .../models/error.py | 107 ++++ .../models/error_payload.py | 43 ++ .../models/errors_code.py | 108 ++++ .../models/errors_code_payload.py | 43 ++ .../models/file_response.py | 130 +++++ .../models/get_chat_response_200.py | 71 +++ .../models/get_chat_response_404.py | 74 +++ .../models/get_chats_availability.py | 9 + .../models/get_chats_response_200.py | 74 +++ .../models/get_chats_response_400.py | 71 +++ .../models/get_chats_response_404.py | 74 +++ .../models/get_chats_response_422.py | 74 +++ .../models/get_chats_sortid.py | 9 + .../models/get_common_methods_response_200.py | 74 +++ .../models/get_employee_response_200.py | 71 +++ .../models/get_employees_response_200.py | 74 +++ .../models/get_list_message_response_200.py | 74 +++ .../models/get_message_reactions_body.py | 68 +++ .../get_message_reactions_response_200.py | 74 +++ .../models/get_message_response_200.py | 71 +++ .../models/get_status_response_200.py | 88 +++ .../models/get_tag_response_200.py | 71 +++ .../models/get_tag_response_404.py | 74 +++ .../get_tag_response_404_errors_item.py | 107 ++++ ...et_tag_response_404_errors_item_payload.py | 43 ++ .../models/get_tags_employees_response_200.py | 74 +++ .../models/get_tags_response_200.py | 74 +++ .../models/get_tags_response_400.py | 74 +++ .../get_tags_response_400_errors_item.py | 107 ++++ ...t_tags_response_400_errors_item_payload.py | 43 ++ .../models/message.py | 272 +++++++++ .../models/message_entity_type.py | 10 + .../models/message_files_item.py | 104 ++++ .../models/message_files_item_file_type.py | 9 + .../models/message_forwarding.py | 153 +++++ .../models/message_thread.py | 67 +++ .../models/not_found.py | 59 ++ .../models/post_members_to_chats_body.py | 69 +++ .../models/post_message_reactions_body.py | 58 ++ .../post_message_reactions_response_400.py | 58 ++ .../post_message_reactions_response_403.py | 58 ++ .../post_message_reactions_response_404.py | 58 ++ .../models/post_tags_to_chats_body.py | 58 ++ .../models/post_tasks_body.py | 71 +++ .../models/post_tasks_body_task.py | 123 ++++ ..._tasks_body_task_custom_properties_item.py | 67 +++ .../models/post_tasks_response_201.py | 71 +++ .../models/post_tasks_response_201_data.py | 177 ++++++ ...esponse_201_data_custom_properties_item.py | 85 +++ .../models/post_tasks_response_400.py | 58 ++ .../models/put_messages_id_body.py | 72 +++ .../models/put_messages_id_response_200.py | 74 +++ .../models/put_status_response_201.py | 88 +++ .../models/query_chat.py | 91 +++ .../models/query_common_methods.py | 77 +++ .../models/query_status.py | 71 +++ .../models/query_status_status.py | 102 ++++ .../models/reaction.py | 86 +++ .../models/status_type_0.py | 101 ++++ .../models/tag.py | 77 +++ .../pachca_api_open_api_3_0_client/py.typed | 1 + .../pachca_api_open_api_3_0_client/types.py | 46 ++ pachca-api-open-api-3-0-client/pyproject.toml | 27 + pachca.py | 26 + pachca_api/.gitignore | 23 + pachca_api/README.md | 124 +++++ .../__init__.py | 8 + .../api/__init__.py | 1 + .../api/chats_and_channels/__init__.py | 0 .../api/chats_and_channels/create_chat.py | 187 +++++++ .../api/chats_and_channels/get_chat.py | 167 ++++++ .../api/chats_and_channels/get_chats.py | 277 +++++++++ .../api/comments/__init__.py | 0 .../api/comments/create_thread.py | 172 ++++++ .../api/common_methods/__init__.py | 0 .../api/common_methods/get_common_methods.py | 175 ++++++ .../api/common_methods/get_direct_url.py | 106 ++++ .../api/common_methods/get_uploads.py | 130 +++++ .../api/employees/__init__.py | 0 .../api/employees/get_employee.py | 167 ++++++ .../api/employees/get_employees.py | 196 +++++++ .../api/messages/__init__.py | 0 .../api/messages/create_message.py | 231 ++++++++ .../api/messages/get_list_message.py | 226 ++++++++ .../api/messages/get_message.py | 171 ++++++ .../api/messages/put_messages_id.py | 200 +++++++ .../api/reactions_to_messages/__init__.py | 0 .../delete_message_reactions.py | 191 +++++++ .../get_message_reactions.py | 195 +++++++ .../post_message_reactions.py | 214 +++++++ .../api/reminders/__init__.py | 0 .../api/reminders/post_tasks.py | 193 +++++++ .../api/status/__init__.py | 0 .../api/status/del_status.py | 83 +++ .../api/status/get_status.py | 134 +++++ .../api/status/put_status.py | 173 ++++++ .../api/tags/__init__.py | 0 .../api/tags/get_tag.py | 163 ++++++ .../api/tags/get_tags.py | 186 +++++++ .../api/tags/get_tags_employees.py | 199 +++++++ .../talk_and_channel_participants/__init__.py | 0 .../delete_chats_id_leave.py | 175 ++++++ .../post_members_to_chats.py | 189 +++++++ .../post_tags_to_chats.py | 189 +++++++ .../pachca_api_open_api_3_0_client/client.py | 268 +++++++++ .../pachca_api_open_api_3_0_client/errors.py | 16 + .../models/__init__.py | 189 +++++++ .../models/bad_request.py | 67 +++ .../models/base_employee.py | 186 +++++++ .../base_employee_custom_properties_item.py | 85 +++ .../models/button.py | 78 +++ .../models/chat.py | 162 ++++++ .../models/create_chat_body.py | 71 +++ .../models/create_chat_response_201.py | 71 +++ .../models/create_chat_response_400.py | 74 +++ .../models/create_chat_response_404.py | 74 +++ .../models/create_chat_response_422.py | 74 +++ .../models/create_message.py | 178 ++++++ .../models/create_message_body.py | 71 +++ .../models/create_message_entity_type.py | 10 + .../models/create_message_files_item.py | 84 +++ .../create_message_files_item_file_type.py | 9 + .../models/create_message_response_201.py | 71 +++ .../models/create_thread_response_200.py | 71 +++ .../models/create_thread_response_200_data.py | 104 ++++ .../delete_message_reactions_response_400.py | 76 +++ ...sage_reactions_response_400_errors_item.py | 111 ++++ ...ctions_response_400_errors_item_payload.py | 43 ++ .../delete_message_reactions_response_404.py | 76 +++ ...sage_reactions_response_404_errors_item.py | 111 ++++ ...ctions_response_404_errors_item_payload.py | 43 ++ .../models/direct_response.py | 195 +++++++ .../models/edit_messages.py | 113 ++++ .../models/edit_messages_buttons_item_item.py | 76 +++ .../models/edit_messages_files.py | 95 ++++ .../models/edit_messages_files_file_type.py | 9 + .../models/employee.py | 275 +++++++++ .../models/error.py | 107 ++++ .../models/error_payload.py | 43 ++ .../models/errors_code.py | 108 ++++ .../models/errors_code_payload.py | 43 ++ .../models/file_response.py | 130 +++++ .../models/get_chat_response_200.py | 71 +++ .../models/get_chat_response_404.py | 74 +++ .../models/get_chats_availability.py | 9 + .../models/get_chats_response_200.py | 74 +++ .../models/get_chats_response_400.py | 71 +++ .../models/get_chats_response_404.py | 74 +++ .../models/get_chats_response_422.py | 74 +++ .../models/get_chats_sortid.py | 9 + .../models/get_common_methods_response_200.py | 74 +++ .../models/get_employee_response_200.py | 71 +++ .../models/get_employees_response_200.py | 74 +++ .../models/get_list_message_response_200.py | 74 +++ .../models/get_message_reactions_body.py | 68 +++ .../get_message_reactions_response_200.py | 74 +++ .../models/get_message_response_200.py | 71 +++ .../models/get_status_response_200.py | 88 +++ .../models/get_tag_response_200.py | 71 +++ .../models/get_tag_response_404.py | 74 +++ .../get_tag_response_404_errors_item.py | 107 ++++ ...et_tag_response_404_errors_item_payload.py | 43 ++ .../models/get_tags_employees_response_200.py | 74 +++ .../models/get_tags_response_200.py | 74 +++ .../models/get_tags_response_400.py | 74 +++ .../get_tags_response_400_errors_item.py | 107 ++++ ...t_tags_response_400_errors_item_payload.py | 43 ++ .../models/message.py | 272 +++++++++ .../models/message_entity_type.py | 10 + .../models/message_files_item.py | 104 ++++ .../models/message_files_item_file_type.py | 9 + .../models/message_forwarding.py | 153 +++++ .../models/message_thread.py | 67 +++ .../models/not_found.py | 59 ++ .../models/post_members_to_chats_body.py | 69 +++ .../models/post_message_reactions_body.py | 58 ++ .../post_message_reactions_response_400.py | 58 ++ .../post_message_reactions_response_403.py | 58 ++ .../post_message_reactions_response_404.py | 58 ++ .../models/post_tags_to_chats_body.py | 58 ++ .../models/post_tasks_body.py | 71 +++ .../models/post_tasks_body_task.py | 123 ++++ ..._tasks_body_task_custom_properties_item.py | 67 +++ .../models/post_tasks_response_201.py | 71 +++ .../models/post_tasks_response_201_data.py | 177 ++++++ ...esponse_201_data_custom_properties_item.py | 85 +++ .../models/post_tasks_response_400.py | 58 ++ .../models/put_messages_id_body.py | 72 +++ .../models/put_messages_id_response_200.py | 74 +++ .../models/put_status_response_201.py | 88 +++ .../models/query_chat.py | 91 +++ .../models/query_common_methods.py | 77 +++ .../models/query_status.py | 71 +++ .../models/query_status_status.py | 102 ++++ .../models/reaction.py | 86 +++ .../models/status_type_0.py | 101 ++++ .../models/tag.py | 77 +++ .../pachca_api_open_api_3_0_client/py.typed | 1 + .../pachca_api_open_api_3_0_client/types.py | 46 ++ pachca_api/pyproject.toml | 27 + templates_api/endpoint_macros.py.jinja | 186 +++++++ templates_api/endpoint_module_api.py.jinja | 527 ++++++++++++++++++ 275 files changed, 26399 insertions(+) create mode 100644 pachca-api-open-api-3-0-client/.gitignore create mode 100644 pachca-api-open-api-3-0-client/README.md create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed create mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py create mode 100644 pachca-api-open-api-3-0-client/pyproject.toml create mode 100644 pachca.py create mode 100644 pachca_api/.gitignore create mode 100644 pachca_api/README.md create mode 100644 pachca_api/pachca_api_open_api_3_0_client/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/comments/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/comments/create_thread.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/common_methods/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/employees/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employee.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employees.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/messages/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/messages/create_message.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/messages/get_list_message.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/messages/get_message.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/reminders/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/status/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/status/del_status.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/status/get_status.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/status/put_status.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/tags/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tag.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/client.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/errors.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/__init__.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/bad_request.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/base_employee.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/button.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/chat.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_chat_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_201.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_400.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_404.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_422.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_message.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_message_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_message_entity_type.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_message_response_201.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/direct_response.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/edit_messages.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/employee.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/error.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/error_payload.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/errors_code.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/errors_code_payload.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/file_response.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_404.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chats_availability.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_400.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_404.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_422.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_chats_sortid.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_employee_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_employees_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_message_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_status_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/message.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/message_entity_type.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/message_files_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/message_forwarding.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/message_thread.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/not_found.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_body.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/put_status_response_201.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/query_chat.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/query_common_methods.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/query_status.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/query_status_status.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/reaction.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/status_type_0.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/models/tag.py create mode 100644 pachca_api/pachca_api_open_api_3_0_client/py.typed create mode 100644 pachca_api/pachca_api_open_api_3_0_client/types.py create mode 100644 pachca_api/pyproject.toml create mode 100644 templates_api/endpoint_macros.py.jinja create mode 100644 templates_api/endpoint_module_api.py.jinja diff --git a/pachca-api-open-api-3-0-client/.gitignore b/pachca-api-open-api-3-0-client/.gitignore new file mode 100644 index 0000000..79a2c3d --- /dev/null +++ b/pachca-api-open-api-3-0-client/.gitignore @@ -0,0 +1,23 @@ +__pycache__/ +build/ +dist/ +*.egg-info/ +.pytest_cache/ + +# pyenv +.python-version + +# Environments +.env +.venv + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# JetBrains +.idea/ + +/coverage.xml +/.coverage diff --git a/pachca-api-open-api-3-0-client/README.md b/pachca-api-open-api-3-0-client/README.md new file mode 100644 index 0000000..3bb71ab --- /dev/null +++ b/pachca-api-open-api-3-0-client/README.md @@ -0,0 +1,124 @@ +# pachca-api-open-api-3-0-client +A client library for accessing PachcaAPI - OpenAPI 3.0 + +## Usage +First, create a client: + +```python +from pachca_api_open_api_3_0_client import Client + +client = Client(base_url="https://api.example.com") +``` + +If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: + +```python +from pachca_api_open_api_3_0_client import AuthenticatedClient + +client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") +``` + +Now call your endpoint and use your models: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +with client as client: + my_data: MyDataModel = get_my_data_model.sync(client=client) + # or if you need more info (e.g. status_code) + response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) +``` + +Or do the same thing with an async version: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +async with client as client: + my_data: MyDataModel = await get_my_data_model.asyncio(client=client) + response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) +``` + +By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl="/path/to/certificate_bundle.pem", +) +``` + +You can also disable certificate validation altogether, but beware that **this is a security risk**. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl=False +) +``` + +Things to know: +1. Every path/method combo becomes a Python module with four functions: + 1. `sync`: Blocking request that returns parsed data (if successful) or `None` + 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. + 1. `asyncio`: Like `sync` but async instead of blocking + 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking + +1. All path/query params, and bodies become method arguments. +1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) +1. Any endpoint which did not have a tag will be in `pachca_api_open_api_3_0_client.api.default` + +## Advanced customizations + +There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): + +```python +from pachca_api_open_api_3_0_client import Client + +def log_request(request): + print(f"Request event hook: {request.method} {request.url} - Waiting for response") + +def log_response(response): + request = response.request + print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") + +client = Client( + base_url="https://api.example.com", + httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, +) + +# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() +``` + +You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): + +```python +import httpx +from pachca_api_open_api_3_0_client import Client + +client = Client( + base_url="https://api.example.com", +) +# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. +client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) +``` + +## Building / publishing this package +This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: +1. Update the metadata in pyproject.toml (e.g. authors, version) +1. If you're using a private repository, configure it with Poetry + 1. `poetry config repositories. ` + 1. `poetry config http-basic. ` +1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` + +If you want to install this client into another project without publishing it (e.g. for development) then: +1. If that project **is using Poetry**, you can simply do `poetry add ` from that project +1. If that project is not using Poetry: + 1. Build a wheel with `poetry build -f wheel` + 1. Install that wheel from the other project `pip install ` diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py new file mode 100644 index 0000000..3a6c9f0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py @@ -0,0 +1,8 @@ +"""A client library for accessing PachcaAPI - OpenAPI 3.0""" + +from .client import AuthenticatedClient, Client + +__all__ = ( + "AuthenticatedClient", + "Client", +) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py new file mode 100644 index 0000000..81f9fa2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py @@ -0,0 +1 @@ +"""Contains methods for accessing the API""" diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py new file mode 100644 index 0000000..028933e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -0,0 +1,187 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.create_chat_body import CreateChatBody +from ...models.create_chat_response_201 import CreateChatResponse201 +from ...models.create_chat_response_400 import CreateChatResponse400 +from ...models.create_chat_response_404 import CreateChatResponse404 +from ...models.create_chat_response_422 import CreateChatResponse422 +from ...types import Response + + +def _get_kwargs( + *, + body: CreateChatBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/chats", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def createChat( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py new file mode 100644 index 0000000..ee92d5b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -0,0 +1,167 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_chat_response_200 import GetChatResponse200 +from ...models.get_chat_response_404 import GetChatResponse404 +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/chats/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatResponse200, GetChatResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatResponse200, GetChatResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getChat( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py new file mode 100644 index 0000000..3443b7c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -0,0 +1,277 @@ +import datetime +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_chats_availability import GetChatsAvailability +from ...models.get_chats_response_200 import GetChatsResponse200 +from ...models.get_chats_response_400 import GetChatsResponse400 +from ...models.get_chats_response_404 import GetChatsResponse404 +from ...models.get_chats_response_422 import GetChatsResponse422 +from ...models.get_chats_sortid import GetChatsSortid +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + + params["sort[id]"] = json_sortid + + params["per"] = per + + params["page"] = page + + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + + params["availability"] = json_availability + + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params["last_message_at_after"] = json_last_message_at_after + + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params["last_message_at_before"] = json_last_message_at_before + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/chats", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + + kwargs = _get_kwargs( + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + + return sync_detailed( + client=client, + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + + kwargs = _get_kwargs( + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getChats( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + + return ( + await asyncio_detailed( + client=client, + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py new file mode 100644 index 0000000..515366b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -0,0 +1,172 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.create_thread_response_200 import CreateThreadResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/thread", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def createThread( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py new file mode 100644 index 0000000..96da5ca --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -0,0 +1,175 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from ...types import UNSET, Response + + +def _get_kwargs( + *, + entity_type: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["entity_type"] = entity_type + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/custom_properties", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + + kwargs = _get_kwargs( + entity_type=entity_type, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + + return sync_detailed( + client=client, + entity_type=entity_type, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + + kwargs = _get_kwargs( + entity_type=entity_type, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getCommonMethods( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + + return ( + await asyncio_detailed( + client=client, + entity_type=entity_type, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py new file mode 100644 index 0000000..9d9e1d5 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py @@ -0,0 +1,106 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.direct_response import DirectResponse +from ...types import Response + + +def _get_kwargs( + *, + body: DirectResponse, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/direct_url", + } + + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: DirectResponse, +) -> Response[Any]: + """Получение URL для загрузки + + Отправляет запрос для получения URL для безопасной загрузки файла. + + Args: + body (DirectResponse): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: DirectResponse, +) -> Response[Any]: + """Получение URL для загрузки + + Отправляет запрос для получения URL для безопасной загрузки файла. + + Args: + body (DirectResponse): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py new file mode 100644 index 0000000..205bacc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -0,0 +1,130 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.file_response import FileResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/uploads", + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[FileResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[FileResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[FileResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getUploads( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py new file mode 100644 index 0000000..c2c698c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -0,0 +1,167 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_employee_response_200 import GetEmployeeResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/users/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetEmployeeResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetEmployeeResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getEmployee( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py new file mode 100644 index 0000000..9a0d658 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_employees_response_200 import GetEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params["query"] = query + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[GetEmployeesResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + query=query, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + + return sync_detailed( + client=client, + per=per, + page=page, + query=query, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + query=query, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getEmployees( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + + return ( + await asyncio_detailed( + client=client, + per=per, + page=page, + query=query, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py new file mode 100644 index 0000000..65100cc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -0,0 +1,231 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.create_message_body import CreateMessageBody +from ...models.create_message_response_201 import CreateMessageResponse201 +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + *, + body: CreateMessageBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/messages", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + response_404.append(componentsschemas_errors_item) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def createMessage( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py new file mode 100644 index 0000000..3627271 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -0,0 +1,226 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_list_message_response_200 import GetListMessageResponse200 +from ...models.not_found import NotFound +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["chat_id"] = chat_id + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/messages", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetListMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + chat_id=chat_id, + per=per, + page=page, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + + return sync_detailed( + client=client, + chat_id=chat_id, + per=per, + page=page, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + chat_id=chat_id, + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getListMessage( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + client=client, + chat_id=chat_id, + per=per, + page=page, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py new file mode 100644 index 0000000..a908b75 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -0,0 +1,171 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_message_response_200 import GetMessageResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getMessage( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py new file mode 100644 index 0000000..19326f6 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py @@ -0,0 +1,200 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.put_messages_id_body import PutMessagesIdBody +from ...models.put_messages_id_response_200 import PutMessagesIdResponse200 +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: PutMessagesIdBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": f"/messages/{id}", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = PutMessagesIdResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PutMessagesIdResponse200, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def put_messages_id( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PutMessagesIdResponse200, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py new file mode 100644 index 0000000..4238fa1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -0,0 +1,191 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from ...types import UNSET, Response + + +def _get_kwargs( + id: str, + *, + code: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["code"] = code + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/messages/{id}/reactions", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + code=code, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + + return sync_detailed( + id=id, + client=client, + code=code, + ).parsed + + +async def asyncio_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + code=code, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def deleteMessageReactions( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + code=code, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py new file mode 100644 index 0000000..fd14687 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_message_reactions_body import GetMessageReactionsBody +from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: GetMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getMessageReactions( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py new file mode 100644 index 0000000..3f26d41 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -0,0 +1,214 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_message_reactions_body import PostMessageReactionsBody +from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from ...types import Response + + +def _get_kwargs( + id: str, + *, + body: PostMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def postMessageReactions( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py new file mode 100644 index 0000000..c037e8a --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py @@ -0,0 +1,193 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_tasks_body import PostTasksBody +from ...models.post_tasks_response_201 import PostTasksResponse201 +from ...models.post_tasks_response_400 import PostTasksResponse400 +from ...types import Response + + +def _get_kwargs( + *, + body: PostTasksBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tasks", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = PostTasksResponse400.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PostTasksResponse201, PostTasksResponse400]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PostTasksResponse201, PostTasksResponse400] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PostTasksResponse201, PostTasksResponse400]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def post_tasks( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PostTasksResponse201, PostTasksResponse400] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py new file mode 100644 index 0000000..1b7bdb9 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py @@ -0,0 +1,83 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py new file mode 100644 index 0000000..e070ad8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -0,0 +1,134 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_status_response_200 import GetStatusResponse200 +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[GetStatusResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetStatusResponse200] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetStatusResponse200] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getStatus( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py new file mode 100644 index 0000000..dd577ec --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.put_status_response_201 import PutStatusResponse201 +from ...models.query_status import QueryStatus +from ...types import Response + + +def _get_kwargs( + *, + body: QueryStatus, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/profile/status", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, PutStatusResponse201]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, PutStatusResponse201]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def putStatus( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py new file mode 100644 index 0000000..420458e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -0,0 +1,163 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_tag_response_200 import GetTagResponse200 +from ...models.get_tag_response_404 import GetTagResponse404 +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagResponse200, GetTagResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagResponse200, GetTagResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getTag( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py new file mode 100644 index 0000000..c9266a2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -0,0 +1,186 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_tags_response_200 import GetTagsResponse200 +from ...models.get_tags_response_400 import GetTagsResponse400 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/group_tags", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + + return sync_detailed( + client=client, + per=per, + page=page, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getTags( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + + return ( + await asyncio_detailed( + client=client, + per=per, + page=page, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py new file mode 100644 index 0000000..b9c0b98 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -0,0 +1,199 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: int, + *, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}/users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetTagsEmployeesResponse200]] + """ + + kwargs = _get_kwargs( + id=id, + per=per, + page=page, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + + return sync_detailed( + id=id, + client=client, + per=per, + page=page, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetTagsEmployeesResponse200]] + """ + + kwargs = _get_kwargs( + id=id, + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def getTagsEmployees( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + per=per, + page=page, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py new file mode 100644 index 0000000..764190e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py @@ -0,0 +1,175 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/chats/{id}/leave", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def delete_chats_id_leave( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py new file mode 100644 index 0000000..6e2e7dc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.post_members_to_chats_body import PostMembersToChatsBody +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: PostMembersToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/members", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def postMembersToChats( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py new file mode 100644 index 0000000..d7dcf81 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.post_tags_to_chats_body import PostTagsToChatsBody +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: PostTagsToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/group_tags", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def postTagsToChats( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py new file mode 100644 index 0000000..ae46a1e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -0,0 +1,274 @@ +import ssl +from typing import Any, Optional, Union + +import httpx +from attrs import define, evolve, field + + +@define +class Client: + """A class for keeping track of data related to the API + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class Pachca: + def __init__(self, base_url, token: str): + self.client = AuthenticatedClient(base_url=base_url, token=token) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py new file mode 100644 index 0000000..5f92e76 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py @@ -0,0 +1,16 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py new file mode 100644 index 0000000..bf2d6c3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py @@ -0,0 +1,189 @@ +"""Contains all the data models used in inputs/outputs""" + +from .bad_request import BadRequest +from .base_employee import BaseEmployee +from .base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem +from .button import Button +from .chat import Chat +from .create_chat_body import CreateChatBody +from .create_chat_response_201 import CreateChatResponse201 +from .create_chat_response_400 import CreateChatResponse400 +from .create_chat_response_404 import CreateChatResponse404 +from .create_chat_response_422 import CreateChatResponse422 +from .create_message import CreateMessage +from .create_message_body import CreateMessageBody +from .create_message_entity_type import CreateMessageEntityType +from .create_message_files_item import CreateMessageFilesItem +from .create_message_files_item_file_type import CreateMessageFilesItemFileType +from .create_message_response_201 import CreateMessageResponse201 +from .create_thread_response_200 import CreateThreadResponse200 +from .create_thread_response_200_data import CreateThreadResponse200Data +from .delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from .delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem +from .delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, +) +from .delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem +from .delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, +) +from .direct_response import DirectResponse +from .edit_messages import EditMessages +from .edit_messages_buttons_item_item import EditMessagesButtonsItemItem +from .edit_messages_files import EditMessagesFiles +from .edit_messages_files_file_type import EditMessagesFilesFileType +from .employee import Employee +from .error import Error +from .error_payload import ErrorPayload +from .errors_code import ErrorsCode +from .errors_code_payload import ErrorsCodePayload +from .file_response import FileResponse +from .get_chat_response_200 import GetChatResponse200 +from .get_chat_response_404 import GetChatResponse404 +from .get_chats_availability import GetChatsAvailability +from .get_chats_response_200 import GetChatsResponse200 +from .get_chats_response_400 import GetChatsResponse400 +from .get_chats_response_404 import GetChatsResponse404 +from .get_chats_response_422 import GetChatsResponse422 +from .get_chats_sortid import GetChatsSortid +from .get_common_methods_response_200 import GetCommonMethodsResponse200 +from .get_employee_response_200 import GetEmployeeResponse200 +from .get_employees_response_200 import GetEmployeesResponse200 +from .get_list_message_response_200 import GetListMessageResponse200 +from .get_message_reactions_body import GetMessageReactionsBody +from .get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .get_message_response_200 import GetMessageResponse200 +from .get_status_response_200 import GetStatusResponse200 +from .get_tag_response_200 import GetTagResponse200 +from .get_tag_response_404 import GetTagResponse404 +from .get_tag_response_404_errors_item import GetTagResponse404ErrorsItem +from .get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload +from .get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .get_tags_response_200 import GetTagsResponse200 +from .get_tags_response_400 import GetTagsResponse400 +from .get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem +from .get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload +from .message import Message +from .message_entity_type import MessageEntityType +from .message_files_item import MessageFilesItem +from .message_files_item_file_type import MessageFilesItemFileType +from .message_forwarding import MessageForwarding +from .message_thread import MessageThread +from .not_found import NotFound +from .post_members_to_chats_body import PostMembersToChatsBody +from .post_message_reactions_body import PostMessageReactionsBody +from .post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .post_tags_to_chats_body import PostTagsToChatsBody +from .post_tasks_body import PostTasksBody +from .post_tasks_body_task import PostTasksBodyTask +from .post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem +from .post_tasks_response_201 import PostTasksResponse201 +from .post_tasks_response_201_data import PostTasksResponse201Data +from .post_tasks_response_201_data_custom_properties_item import PostTasksResponse201DataCustomPropertiesItem +from .post_tasks_response_400 import PostTasksResponse400 +from .put_messages_id_body import PutMessagesIdBody +from .put_messages_id_response_200 import PutMessagesIdResponse200 +from .put_status_response_201 import PutStatusResponse201 +from .query_chat import QueryChat +from .query_common_methods import QueryCommonMethods +from .query_status import QueryStatus +from .query_status_status import QueryStatusStatus +from .reaction import Reaction +from .status_type_0 import StatusType0 +from .tag import Tag + +__all__ = ( + "BadRequest", + "BaseEmployee", + "BaseEmployeeCustomPropertiesItem", + "Button", + "Chat", + "CreateChatBody", + "CreateChatResponse201", + "CreateChatResponse400", + "CreateChatResponse404", + "CreateChatResponse422", + "CreateMessage", + "CreateMessageBody", + "CreateMessageEntityType", + "CreateMessageFilesItem", + "CreateMessageFilesItemFileType", + "CreateMessageResponse201", + "CreateThreadResponse200", + "CreateThreadResponse200Data", + "DeleteMessageReactionsResponse400", + "DeleteMessageReactionsResponse400ErrorsItem", + "DeleteMessageReactionsResponse400ErrorsItemPayload", + "DeleteMessageReactionsResponse404", + "DeleteMessageReactionsResponse404ErrorsItem", + "DeleteMessageReactionsResponse404ErrorsItemPayload", + "DirectResponse", + "EditMessages", + "EditMessagesButtonsItemItem", + "EditMessagesFiles", + "EditMessagesFilesFileType", + "Employee", + "Error", + "ErrorPayload", + "ErrorsCode", + "ErrorsCodePayload", + "FileResponse", + "GetChatResponse200", + "GetChatResponse404", + "GetChatsAvailability", + "GetChatsResponse200", + "GetChatsResponse400", + "GetChatsResponse404", + "GetChatsResponse422", + "GetChatsSortid", + "GetCommonMethodsResponse200", + "GetEmployeeResponse200", + "GetEmployeesResponse200", + "GetListMessageResponse200", + "GetMessageReactionsBody", + "GetMessageReactionsResponse200", + "GetMessageResponse200", + "GetStatusResponse200", + "GetTagResponse200", + "GetTagResponse404", + "GetTagResponse404ErrorsItem", + "GetTagResponse404ErrorsItemPayload", + "GetTagsEmployeesResponse200", + "GetTagsResponse200", + "GetTagsResponse400", + "GetTagsResponse400ErrorsItem", + "GetTagsResponse400ErrorsItemPayload", + "Message", + "MessageEntityType", + "MessageFilesItem", + "MessageFilesItemFileType", + "MessageForwarding", + "MessageThread", + "NotFound", + "PostMembersToChatsBody", + "PostMessageReactionsBody", + "PostMessageReactionsResponse400", + "PostMessageReactionsResponse403", + "PostMessageReactionsResponse404", + "PostTagsToChatsBody", + "PostTasksBody", + "PostTasksBodyTask", + "PostTasksBodyTaskCustomPropertiesItem", + "PostTasksResponse201", + "PostTasksResponse201Data", + "PostTasksResponse201DataCustomPropertiesItem", + "PostTasksResponse400", + "PutMessagesIdBody", + "PutMessagesIdResponse200", + "PutStatusResponse201", + "QueryChat", + "QueryCommonMethods", + "QueryStatus", + "QueryStatusStatus", + "Reaction", + "StatusType0", + "Tag", +) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py new file mode 100644 index 0000000..17dd6ed --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BadRequest") + + +@_attrs_define +class BadRequest: + """ + Attributes: + error (Union[Unset, str]): + message (Union[Unset, str]): + """ + + error: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + message = d.pop("message", UNSET) + + bad_request = cls( + error=error, + message=message, + ) + + bad_request.additional_properties = d + return bad_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py new file mode 100644 index 0000000..b6a0314 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py @@ -0,0 +1,186 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + +T = TypeVar("T", bound="BaseEmployee") + + +@_attrs_define +class BaseEmployee: + """Базовый класс сотрудника. + + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + base_employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + ) + + base_employee.additional_properties = d + return base_employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py new file mode 100644 index 0000000..bee25c8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BaseEmployeeCustomPropertiesItem") + + +@_attrs_define +class BaseEmployeeCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + base_employee_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + base_employee_custom_properties_item.additional_properties = d + return base_employee_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py new file mode 100644 index 0000000..64ea323 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py @@ -0,0 +1,78 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Button") + + +@_attrs_define +class Button: + """ + Attributes: + text (str): + url (Union[Unset, str]): + data (Union[Unset, str]): + """ + + text: str + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + } + ) + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text") + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + button = cls( + text=text, + url=url, + data=data, + ) + + button.additional_properties = d + return button + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py new file mode 100644 index 0000000..7ef2560 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py @@ -0,0 +1,162 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Chat") + + +@_attrs_define +class Chat: + """Беседа или канал + + Attributes: + id (Union[Unset, int]): Идентификатор беседы или канала Example: 334. + name (Union[Unset, str]): Название Example: 🤿 aqua. + owner_id (Union[Unset, int]): Идентификатор пользователя, создавшего беседу или канал Example: 185. + created_at (Union[Unset, datetime.datetime]): Дата и время создания беседы или канала (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:56:53.000Z. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, участников Example: [185, 186, 187]. + group_tag_ids (Union[Unset, list[int]]): Массив идентификаторов тегов, участников + channel (Union[Unset, bool]): Тип: беседа (false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (false) или открытый (true) + last_message_at (Union[Unset, datetime.datetime]): Дата и время создания последнего сообщения в беседе/канале + (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:58:13.000Z. + meet_room_url (Union[Unset, str]): Ссылка на Видеочат Example: https://meet.pachca.com/aqua-94bb21b5. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + owner_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + member_ids: Union[Unset, list[int]] = UNSET + group_tag_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + last_message_at: Union[Unset, datetime.datetime] = UNSET + meet_room_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + owner_id = self.owner_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + group_tag_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.group_tag_ids, Unset): + group_tag_ids = self.group_tag_ids + + channel = self.channel + + public = self.public + + last_message_at: Union[Unset, str] = UNSET + if not isinstance(self.last_message_at, Unset): + last_message_at = self.last_message_at.isoformat() + + meet_room_url = self.meet_room_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if owner_id is not UNSET: + field_dict["owner_id"] = owner_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if group_tag_ids is not UNSET: + field_dict["group_tag_ids"] = group_tag_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + if last_message_at is not UNSET: + field_dict["last_message_at"] = last_message_at + if meet_room_url is not UNSET: + field_dict["meet_room_url"] = meet_room_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + owner_id = d.pop("owner_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + group_tag_ids = cast(list[int], d.pop("group_tag_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + _last_message_at = d.pop("last_message_at", UNSET) + last_message_at: Union[Unset, datetime.datetime] + if isinstance(_last_message_at, Unset): + last_message_at = UNSET + else: + last_message_at = isoparse(_last_message_at) + + meet_room_url = d.pop("meet_room_url", UNSET) + + chat = cls( + id=id, + name=name, + owner_id=owner_id, + created_at=created_at, + member_ids=member_ids, + group_tag_ids=group_tag_ids, + channel=channel, + public=public, + last_message_at=last_message_at, + meet_room_url=meet_room_url, + ) + + chat.additional_properties = d + return chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py new file mode 100644 index 0000000..8b9e361 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_chat import QueryChat + + +T = TypeVar("T", bound="CreateChatBody") + + +@_attrs_define +class CreateChatBody: + """ + Attributes: + chat (Union[Unset, QueryChat]): Собранный объект параметров создаваемой беседы или канала + """ + + chat: Union[Unset, "QueryChat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + chat: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.chat, Unset): + chat = self.chat.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if chat is not UNSET: + field_dict["chat"] = chat + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_chat import QueryChat + + d = src_dict.copy() + _chat = d.pop("chat", UNSET) + chat: Union[Unset, QueryChat] + if isinstance(_chat, Unset): + chat = UNSET + else: + chat = QueryChat.from_dict(_chat) + + create_chat_body = cls( + chat=chat, + ) + + create_chat_body.additional_properties = d + return create_chat_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py new file mode 100644 index 0000000..3a928ef --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="CreateChatResponse201") + + +@_attrs_define +class CreateChatResponse201: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + create_chat_response_201 = cls( + data=data, + ) + + create_chat_response_201.additional_properties = d + return create_chat_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py new file mode 100644 index 0000000..1d7fd30 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse400") + + +@_attrs_define +class CreateChatResponse400: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_400 = cls( + errors=errors, + ) + + create_chat_response_400.additional_properties = d + return create_chat_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py new file mode 100644 index 0000000..3de2654 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse404") + + +@_attrs_define +class CreateChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_404 = cls( + errors=errors, + ) + + create_chat_response_404.additional_properties = d + return create_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py new file mode 100644 index 0000000..c917758 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse422") + + +@_attrs_define +class CreateChatResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_422 = cls( + errors=errors, + ) + + create_chat_response_422.additional_properties = d + return create_chat_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py new file mode 100644 index 0000000..63e52de --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py @@ -0,0 +1,178 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_entity_type import CreateMessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + +T = TypeVar("T", bound="CreateMessage") + + +@_attrs_define +class CreateMessage: + """ + Attributes: + entity_id (int): + content (str): + entity_type (Union[Unset, CreateMessageEntityType]): Default: CreateMessageEntityType.DISCUSSION. + files (Union[Unset, list['CreateMessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + parent_message_id (Union[None, Unset, int]): + skip_invite_mentions (Union[Unset, bool]): Default: False. + link_preview (Union[Unset, bool]): Default: False. + """ + + entity_id: int + content: str + entity_type: Union[Unset, CreateMessageEntityType] = CreateMessageEntityType.DISCUSSION + files: Union[Unset, list["CreateMessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + skip_invite_mentions: Union[Unset, bool] = False + link_preview: Union[Unset, bool] = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + content = self.content + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + skip_invite_mentions = self.skip_invite_mentions + + link_preview = self.link_preview + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "content": content, + } + ) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + if skip_invite_mentions is not UNSET: + field_dict["skip_invite_mentions"] = skip_invite_mentions + if link_preview is not UNSET: + field_dict["link_preview"] = link_preview + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + d = src_dict.copy() + entity_id = d.pop("entity_id") + + content = d.pop("content") + + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, CreateMessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = CreateMessageEntityType(_entity_type) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = CreateMessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + skip_invite_mentions = d.pop("skip_invite_mentions", UNSET) + + link_preview = d.pop("link_preview", UNSET) + + create_message = cls( + entity_id=entity_id, + content=content, + entity_type=entity_type, + files=files, + buttons=buttons, + parent_message_id=parent_message_id, + skip_invite_mentions=skip_invite_mentions, + link_preview=link_preview, + ) + + create_message.additional_properties = d + return create_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py new file mode 100644 index 0000000..a8960fe --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_message import CreateMessage + + +T = TypeVar("T", bound="CreateMessageBody") + + +@_attrs_define +class CreateMessageBody: + """ + Attributes: + message (Union[Unset, CreateMessage]): + """ + + message: Union[Unset, "CreateMessage"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_message import CreateMessage + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, CreateMessage] + if isinstance(_message, Unset): + message = UNSET + else: + message = CreateMessage.from_dict(_message) + + create_message_body = cls( + message=message, + ) + + create_message_body.additional_properties = d + return create_message_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py new file mode 100644 index 0000000..067c6f4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class CreateMessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py new file mode 100644 index 0000000..a7c8ee3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py @@ -0,0 +1,84 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_files_item_file_type import CreateMessageFilesItemFileType + +T = TypeVar("T", bound="CreateMessageFilesItem") + + +@_attrs_define +class CreateMessageFilesItem: + """ + Attributes: + key (str): + name (str): + file_type (CreateMessageFilesItemFileType): + size (int): + """ + + key: str + name: str + file_type: CreateMessageFilesItemFileType + size: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "key": key, + "name": name, + "file_type": file_type, + "size": size, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key") + + name = d.pop("name") + + file_type = CreateMessageFilesItemFileType(d.pop("file_type")) + + size = d.pop("size") + + create_message_files_item = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + create_message_files_item.additional_properties = d + return create_message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py new file mode 100644 index 0000000..89889f9 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CreateMessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py new file mode 100644 index 0000000..b016d4c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="CreateMessageResponse201") + + +@_attrs_define +class CreateMessageResponse201: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + create_message_response_201 = cls( + data=data, + ) + + create_message_response_201.additional_properties = d + return create_message_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py new file mode 100644 index 0000000..15fd0b4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + +T = TypeVar("T", bound="CreateThreadResponse200") + + +@_attrs_define +class CreateThreadResponse200: + """ + Attributes: + data (Union[Unset, CreateThreadResponse200Data]): + """ + + data: Union[Unset, "CreateThreadResponse200Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, CreateThreadResponse200Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = CreateThreadResponse200Data.from_dict(_data) + + create_thread_response_200 = cls( + data=data, + ) + + create_thread_response_200.additional_properties = d + return create_thread_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py new file mode 100644 index 0000000..93b7457 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py @@ -0,0 +1,104 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateThreadResponse200Data") + + +@_attrs_define +class CreateThreadResponse200Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного треда. + chat_id (Union[Unset, int]): Идентификатор чата треда. + message_id (Union[Unset, int]): Идентификатор сообщения, к которому был создан тред. + message_chat_id (Union[Unset, int]): Идентификатор чата сообщения. + updated_at (Union[Unset, datetime.datetime]): Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + message_id: Union[Unset, int] = UNSET + message_chat_id: Union[Unset, int] = UNSET + updated_at: Union[Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + message_id = self.message_id + + message_chat_id = self.message_chat_id + + updated_at: Union[Unset, str] = UNSET + if not isinstance(self.updated_at, Unset): + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if message_id is not UNSET: + field_dict["message_id"] = message_id + if message_chat_id is not UNSET: + field_dict["message_chat_id"] = message_chat_id + if updated_at is not UNSET: + field_dict["updated_at"] = updated_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_id = d.pop("message_id", UNSET) + + message_chat_id = d.pop("message_chat_id", UNSET) + + _updated_at = d.pop("updated_at", UNSET) + updated_at: Union[Unset, datetime.datetime] + if isinstance(_updated_at, Unset): + updated_at = UNSET + else: + updated_at = isoparse(_updated_at) + + create_thread_response_200_data = cls( + id=id, + chat_id=chat_id, + message_id=message_id, + message_chat_id=message_chat_id, + updated_at=updated_at, + ) + + create_thread_response_200_data.additional_properties = d + return create_thread_response_200_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py new file mode 100644 index 0000000..100dc9c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400") + + +@_attrs_define +class DeleteMessageReactionsResponse400: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item import ( + DeleteMessageReactionsResponse400ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_400 = cls( + errors=errors, + ) + + delete_message_reactions_response_400.additional_properties = d + return delete_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py new file mode 100644 index 0000000..4a61277 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse400ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_400_errors_item.additional_properties = d + return delete_message_reactions_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py new file mode 100644 index 0000000..d3d26c9 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_400_errors_item_payload = cls() + + delete_message_reactions_response_400_errors_item_payload.additional_properties = d + return delete_message_reactions_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py new file mode 100644 index 0000000..9f918a0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404") + + +@_attrs_define +class DeleteMessageReactionsResponse404: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item import ( + DeleteMessageReactionsResponse404ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_404 = cls( + errors=errors, + ) + + delete_message_reactions_response_404.additional_properties = d + return delete_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py new file mode 100644 index 0000000..849db9d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse404ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_404_errors_item.additional_properties = d + return delete_message_reactions_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py new file mode 100644 index 0000000..f2fa5b5 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_404_errors_item_payload = cls() + + delete_message_reactions_response_404_errors_item_payload.additional_properties = d + return delete_message_reactions_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py new file mode 100644 index 0000000..aef4bc1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py @@ -0,0 +1,195 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DirectResponse") + + +@_attrs_define +class DirectResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + file (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + file: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + file = self.file + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + def to_multipart(self) -> dict[str, Any]: + content_disposition = ( + self.content_disposition + if isinstance(self.content_disposition, Unset) + else (None, str(self.content_disposition).encode(), "text/plain") + ) + + acl = self.acl if isinstance(self.acl, Unset) else (None, str(self.acl).encode(), "text/plain") + + policy = self.policy if isinstance(self.policy, Unset) else (None, str(self.policy).encode(), "text/plain") + + x_amz_credential = ( + self.x_amz_credential + if isinstance(self.x_amz_credential, Unset) + else (None, str(self.x_amz_credential).encode(), "text/plain") + ) + + x_amz_algorithm = ( + self.x_amz_algorithm + if isinstance(self.x_amz_algorithm, Unset) + else (None, str(self.x_amz_algorithm).encode(), "text/plain") + ) + + x_amz_date = ( + self.x_amz_date + if isinstance(self.x_amz_date, Unset) + else (None, str(self.x_amz_date).encode(), "text/plain") + ) + + x_amz_signature = ( + self.x_amz_signature + if isinstance(self.x_amz_signature, Unset) + else (None, str(self.x_amz_signature).encode(), "text/plain") + ) + + key = self.key if isinstance(self.key, Unset) else (None, str(self.key).encode(), "text/plain") + + file = self.file if isinstance(self.file, Unset) else (None, str(self.file).encode(), "text/plain") + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = (None, str(prop).encode(), "text/plain") + + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + file = d.pop("file", UNSET) + + direct_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + file=file, + ) + + direct_response.additional_properties = d + return direct_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py new file mode 100644 index 0000000..8e6439d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py @@ -0,0 +1,113 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + +T = TypeVar("T", bound="EditMessages") + + +@_attrs_define +class EditMessages: + """Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Attributes: + content (Union[Unset, str]): Текст сообщения Default: 'Текст сообщения'. + files (Union[Unset, EditMessagesFiles]): + buttons (Union[Unset, list[list['EditMessagesButtonsItemItem']]]): Массив строк, каждая из которых представлена + массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в + статье. Для удаления кнопок у сообщения пришлите пустой массив. + """ + + content: Union[Unset, str] = "Текст сообщения" + files: Union[Unset, "EditMessagesFiles"] = UNSET + buttons: Union[Unset, list[list["EditMessagesButtonsItemItem"]]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content = self.content + + files: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.files, Unset): + files = self.files.to_dict() + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for buttons_item_data in self.buttons: + buttons_item = [] + for buttons_item_item_data in buttons_item_data: + buttons_item_item = buttons_item_item_data.to_dict() + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content is not UNSET: + field_dict["content"] = content + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + d = src_dict.copy() + content = d.pop("content", UNSET) + + _files = d.pop("files", UNSET) + files: Union[Unset, EditMessagesFiles] + if isinstance(_files, Unset): + files = UNSET + else: + files = EditMessagesFiles.from_dict(_files) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for buttons_item_data in _buttons or []: + buttons_item = [] + _buttons_item = buttons_item_data + for buttons_item_item_data in _buttons_item: + buttons_item_item = EditMessagesButtonsItemItem.from_dict(buttons_item_item_data) + + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + edit_messages = cls( + content=content, + files=files, + buttons=buttons, + ) + + edit_messages.additional_properties = d + return edit_messages + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py new file mode 100644 index 0000000..22494f8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py @@ -0,0 +1,76 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesButtonsItemItem") + + +@_attrs_define +class EditMessagesButtonsItemItem: + """ + Attributes: + text (Union[Unset, str]): Текст, отображаемый на кнопке пользователю + url (Union[Unset, str]): Ссылка, которая будет открыта по нажатию кнопки + data (Union[Unset, str]): Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + """ + + text: Union[Unset, str] = UNSET + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if text is not UNSET: + field_dict["text"] = text + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text", UNSET) + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + edit_messages_buttons_item_item = cls( + text=text, + url=url, + data=data, + ) + + edit_messages_buttons_item_item.additional_properties = d + return edit_messages_buttons_item_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py new file mode 100644 index 0000000..f42b7bb --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py @@ -0,0 +1,95 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.edit_messages_files_file_type import EditMessagesFilesFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesFiles") + + +@_attrs_define +class EditMessagesFiles: + """ + Attributes: + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, EditMessagesFilesFileType]): + size (Union[Unset, int]): Размер файла в байтах, отображаемый пользователю Default: 1234. + """ + + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, EditMessagesFilesFileType] = UNSET + size: Union[Unset, int] = 1234 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if size is not UNSET: + field_dict["size"] = size + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, EditMessagesFilesFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = EditMessagesFilesFileType(_file_type) + + size = d.pop("size", UNSET) + + edit_messages_files = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + edit_messages_files.additional_properties = d + return edit_messages_files + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py new file mode 100644 index 0000000..a78a223 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class EditMessagesFilesFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py new file mode 100644 index 0000000..9011165 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py @@ -0,0 +1,275 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="Employee") + + +@_attrs_define +class Employee: + """ + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + user_status (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + title (Union[Unset, str]): Должность + created_at (Union[Unset, datetime.datetime]): Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone (Union[Unset, str]): Часовой пояс пользователя + image_url (Union[None, Unset, str]): Ссылка на скачивание аватарки + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + user_status: Union["StatusType0", None, Unset] = UNSET + title: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + time_zone: Union[Unset, str] = UNSET + image_url: Union[None, Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + user_status: Union[None, Unset, dict[str, Any]] + if isinstance(self.user_status, Unset): + user_status = UNSET + elif isinstance(self.user_status, StatusType0): + user_status = self.user_status.to_dict() + else: + user_status = self.user_status + + title = self.title + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + time_zone = self.time_zone + + image_url: Union[None, Unset, str] + if isinstance(self.image_url, Unset): + image_url = UNSET + else: + image_url = self.image_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + if user_status is not UNSET: + field_dict["user_status"] = user_status + if title is not UNSET: + field_dict["title"] = title + if created_at is not UNSET: + field_dict["created_at"] = created_at + if time_zone is not UNSET: + field_dict["time_zone"] = time_zone + if image_url is not UNSET: + field_dict["image_url"] = image_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + def _parse_user_status(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + user_status = _parse_user_status(d.pop("user_status", UNSET)) + + title = d.pop("title", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + time_zone = d.pop("time_zone", UNSET) + + def _parse_image_url(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + image_url = _parse_image_url(d.pop("image_url", UNSET)) + + employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + user_status=user_status, + title=title, + created_at=created_at, + time_zone=time_zone, + image_url=image_url, + ) + + employee.additional_properties = d + return employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py new file mode 100644 index 0000000..e9e73d2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error_payload import ErrorPayload + + +T = TypeVar("T", bound="Error") + + +@_attrs_define +class Error: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error_payload import ErrorPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorPayload.from_dict(_payload) + + error = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + error.additional_properties = d + return error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py new file mode 100644 index 0000000..9133249 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorPayload") + + +@_attrs_define +class ErrorPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error_payload = cls() + + error_payload.additional_properties = d + return error_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py new file mode 100644 index 0000000..52b0dee --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py @@ -0,0 +1,108 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code_payload import ErrorsCodePayload + + +T = TypeVar("T", bound="ErrorsCode") + + +@_attrs_define +class ErrorsCode: + """Bad Request + + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorsCodePayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorsCodePayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code_payload import ErrorsCodePayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorsCodePayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorsCodePayload.from_dict(_payload) + + errors_code = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + errors_code.additional_properties = d + return errors_code + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py new file mode 100644 index 0000000..8128de2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorsCodePayload") + + +@_attrs_define +class ErrorsCodePayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + errors_code_payload = cls() + + errors_code_payload.additional_properties = d + return errors_code_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py new file mode 100644 index 0000000..5bb1dc4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py @@ -0,0 +1,130 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FileResponse") + + +@_attrs_define +class FileResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + direct_url (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + direct_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + direct_url = self.direct_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if direct_url is not UNSET: + field_dict["direct_url"] = direct_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + direct_url = d.pop("direct_url", UNSET) + + file_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + direct_url=direct_url, + ) + + file_response.additional_properties = d + return file_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py new file mode 100644 index 0000000..274ed8c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatResponse200") + + +@_attrs_define +class GetChatResponse200: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + get_chat_response_200 = cls( + data=data, + ) + + get_chat_response_200.additional_properties = d + return get_chat_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py new file mode 100644 index 0000000..6aaf8b1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatResponse404") + + +@_attrs_define +class GetChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chat_response_404 = cls( + errors=errors, + ) + + get_chat_response_404.additional_properties = d + return get_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py new file mode 100644 index 0000000..b76cb4d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsAvailability(str, Enum): + IS_MEMBER = "is_member" + PUBLIC = "public" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py new file mode 100644 index 0000000..3917a9f --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatsResponse200") + + +@_attrs_define +class GetChatsResponse200: + """ + Attributes: + data (Union[Unset, list['Chat']]): + """ + + data: Union[Unset, list["Chat"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Chat.from_dict(data_item_data) + + data.append(data_item) + + get_chats_response_200 = cls( + data=data, + ) + + get_chats_response_200.additional_properties = d + return get_chats_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py new file mode 100644 index 0000000..005a6a3 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code import ErrorsCode + + +T = TypeVar("T", bound="GetChatsResponse400") + + +@_attrs_define +class GetChatsResponse400: + """ + Attributes: + errors (Union[Unset, ErrorsCode]): Bad Request + """ + + errors: Union[Unset, "ErrorsCode"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.errors, Unset): + errors = self.errors.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code import ErrorsCode + + d = src_dict.copy() + _errors = d.pop("errors", UNSET) + errors: Union[Unset, ErrorsCode] + if isinstance(_errors, Unset): + errors = UNSET + else: + errors = ErrorsCode.from_dict(_errors) + + get_chats_response_400 = cls( + errors=errors, + ) + + get_chats_response_400.additional_properties = d + return get_chats_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py new file mode 100644 index 0000000..1553a65 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse404") + + +@_attrs_define +class GetChatsResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_404 = cls( + errors=errors, + ) + + get_chats_response_404.additional_properties = d + return get_chats_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py new file mode 100644 index 0000000..5248609 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse422") + + +@_attrs_define +class GetChatsResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_422 = cls( + errors=errors, + ) + + get_chats_response_422.additional_properties = d + return get_chats_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py new file mode 100644 index 0000000..0de410c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsSortid(str, Enum): + ASC = "asc" + DESC = "desc" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py new file mode 100644 index 0000000..93ea91d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_common_methods import QueryCommonMethods + + +T = TypeVar("T", bound="GetCommonMethodsResponse200") + + +@_attrs_define +class GetCommonMethodsResponse200: + """ + Attributes: + data (Union[Unset, list['QueryCommonMethods']]): + """ + + data: Union[Unset, list["QueryCommonMethods"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_common_methods import QueryCommonMethods + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = QueryCommonMethods.from_dict(data_item_data) + + data.append(data_item) + + get_common_methods_response_200 = cls( + data=data, + ) + + get_common_methods_response_200.additional_properties = d + return get_common_methods_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py new file mode 100644 index 0000000..b970ea8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeeResponse200") + + +@_attrs_define +class GetEmployeeResponse200: + """ + Attributes: + data (Union[Unset, Employee]): + """ + + data: Union[Unset, "Employee"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Employee] + if isinstance(_data, Unset): + data = UNSET + else: + data = Employee.from_dict(_data) + + get_employee_response_200 = cls( + data=data, + ) + + get_employee_response_200.additional_properties = d + return get_employee_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py new file mode 100644 index 0000000..978802c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeesResponse200") + + +@_attrs_define +class GetEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['Employee']]): + """ + + data: Union[Unset, list["Employee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Employee.from_dict(data_item_data) + + data.append(data_item) + + get_employees_response_200 = cls( + data=data, + ) + + get_employees_response_200.additional_properties = d + return get_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py new file mode 100644 index 0000000..52837e1 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetListMessageResponse200") + + +@_attrs_define +class GetListMessageResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + get_list_message_response_200 = cls( + data=data, + ) + + get_list_message_response_200.additional_properties = d + return get_list_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py new file mode 100644 index 0000000..eaa7bb5 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py @@ -0,0 +1,68 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="GetMessageReactionsBody") + + +@_attrs_define +class GetMessageReactionsBody: + """ + Attributes: + per (Union[Unset, int]): Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). + Default: 50. + page (Union[Unset, int]): Номер страницы выборки (по умолчанию 1). Default: 1. + """ + + per: Union[Unset, int] = 50 + page: Union[Unset, int] = 1 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + per = self.per + + page = self.page + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if per is not UNSET: + field_dict["per"] = per + if page is not UNSET: + field_dict["page"] = page + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + per = d.pop("per", UNSET) + + page = d.pop("page", UNSET) + + get_message_reactions_body = cls( + per=per, + page=page, + ) + + get_message_reactions_body.additional_properties = d + return get_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py new file mode 100644 index 0000000..3c50c79 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.reaction import Reaction + + +T = TypeVar("T", bound="GetMessageReactionsResponse200") + + +@_attrs_define +class GetMessageReactionsResponse200: + """ + Attributes: + data (Union[Unset, list['Reaction']]): + """ + + data: Union[Unset, list["Reaction"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.reaction import Reaction + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Reaction.from_dict(data_item_data) + + data.append(data_item) + + get_message_reactions_response_200 = cls( + data=data, + ) + + get_message_reactions_response_200.additional_properties = d + return get_message_reactions_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py new file mode 100644 index 0000000..677295d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetMessageResponse200") + + +@_attrs_define +class GetMessageResponse200: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + get_message_response_200 = cls( + data=data, + ) + + get_message_response_200.additional_properties = d + return get_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py new file mode 100644 index 0000000..7e93886 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="GetStatusResponse200") + + +@_attrs_define +class GetStatusResponse200: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + get_status_response_200 = cls( + data=data, + ) + + get_status_response_200.additional_properties = d + return get_status_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py new file mode 100644 index 0000000..188f734 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagResponse200") + + +@_attrs_define +class GetTagResponse200: + """ + Attributes: + data (Union[Unset, Tag]): Для получения тега вам необходимо знать его id и указать его в URL запроса. + """ + + data: Union[Unset, "Tag"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Tag] + if isinstance(_data, Unset): + data = UNSET + else: + data = Tag.from_dict(_data) + + get_tag_response_200 = cls( + data=data, + ) + + get_tag_response_200.additional_properties = d + return get_tag_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py new file mode 100644 index 0000000..c3c8ead --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + +T = TypeVar("T", bound="GetTagResponse404") + + +@_attrs_define +class GetTagResponse404: + """ + Attributes: + errors (Union[Unset, list['GetTagResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["GetTagResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tag_response_404 = cls( + errors=errors, + ) + + get_tag_response_404.additional_properties = d + return get_tag_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py new file mode 100644 index 0000000..18649e6 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagResponse404ErrorsItem") + + +@_attrs_define +class GetTagResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, GetTagResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagResponse404ErrorsItemPayload.from_dict(_payload) + + get_tag_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tag_response_404_errors_item.additional_properties = d + return get_tag_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py new file mode 100644 index 0000000..b6d7c6c --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagResponse404ErrorsItemPayload") + + +@_attrs_define +class GetTagResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tag_response_404_errors_item_payload = cls() + + get_tag_response_404_errors_item_payload.additional_properties = d + return get_tag_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py new file mode 100644 index 0000000..682b3fa --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee import BaseEmployee + + +T = TypeVar("T", bound="GetTagsEmployeesResponse200") + + +@_attrs_define +class GetTagsEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['BaseEmployee']]): + """ + + data: Union[Unset, list["BaseEmployee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee import BaseEmployee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = BaseEmployee.from_dict(data_item_data) + + data.append(data_item) + + get_tags_employees_response_200 = cls( + data=data, + ) + + get_tags_employees_response_200.additional_properties = d + return get_tags_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py new file mode 100644 index 0000000..1ae18d4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagsResponse200") + + +@_attrs_define +class GetTagsResponse200: + """ + Attributes: + data (Union[Unset, list['Tag']]): + """ + + data: Union[Unset, list["Tag"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Tag.from_dict(data_item_data) + + data.append(data_item) + + get_tags_response_200 = cls( + data=data, + ) + + get_tags_response_200.additional_properties = d + return get_tags_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py new file mode 100644 index 0000000..1865c60 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + +T = TypeVar("T", bound="GetTagsResponse400") + + +@_attrs_define +class GetTagsResponse400: + """ + Attributes: + errors (Union[Unset, list['GetTagsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["GetTagsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tags_response_400 = cls( + errors=errors, + ) + + get_tags_response_400.additional_properties = d + return get_tags_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py new file mode 100644 index 0000000..bd7859d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItem") + + +@_attrs_define +class GetTagsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, GetTagsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagsResponse400ErrorsItemPayload.from_dict(_payload) + + get_tags_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tags_response_400_errors_item.additional_properties = d + return get_tags_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py new file mode 100644 index 0000000..2e1d941 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItemPayload") + + +@_attrs_define +class GetTagsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tags_response_400_errors_item_payload = cls() + + get_tags_response_400_errors_item_payload.additional_properties = d + return get_tags_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py new file mode 100644 index 0000000..bb01030 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py @@ -0,0 +1,272 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..models.message_entity_type import MessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + +T = TypeVar("T", bound="Message") + + +@_attrs_define +class Message: + """ + Attributes: + entity_type (Union[Unset, MessageEntityType]): Default: MessageEntityType.DISCUSSION. + entity_id (Union[Unset, int]): + content (Union[Unset, str]): + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + user_id (Union[Unset, int]): + created_at (Union[Unset, datetime.datetime]): + files (Union[Unset, list['MessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + thread (Union['MessageThread', None, Unset]): + forwarding (Union['MessageForwarding', None, Unset]): + parent_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому написан ответ. Возвращается как + null, если сообщение не является ответом. + """ + + entity_type: Union[Unset, MessageEntityType] = MessageEntityType.DISCUSSION + entity_id: Union[Unset, int] = UNSET + content: Union[Unset, str] = UNSET + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + files: Union[Unset, list["MessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + thread: Union["MessageThread", None, Unset] = UNSET + forwarding: Union["MessageForwarding", None, Unset] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + entity_id = self.entity_id + + content = self.content + + id = self.id + + chat_id = self.chat_id + + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + thread: Union[None, Unset, dict[str, Any]] + if isinstance(self.thread, Unset): + thread = UNSET + elif isinstance(self.thread, MessageThread): + thread = self.thread.to_dict() + else: + thread = self.thread + + forwarding: Union[None, Unset, dict[str, Any]] + if isinstance(self.forwarding, Unset): + forwarding = UNSET + elif isinstance(self.forwarding, MessageForwarding): + forwarding = self.forwarding.to_dict() + else: + forwarding = self.forwarding + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if entity_id is not UNSET: + field_dict["entity_id"] = entity_id + if content is not UNSET: + field_dict["content"] = content + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if thread is not UNSET: + field_dict["thread"] = thread + if forwarding is not UNSET: + field_dict["forwarding"] = forwarding + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + d = src_dict.copy() + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, MessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = MessageEntityType(_entity_type) + + entity_id = d.pop("entity_id", UNSET) + + content = d.pop("content", UNSET) + + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = MessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_thread(data: object) -> Union["MessageThread", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + thread_type_0 = MessageThread.from_dict(data) + + return thread_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageThread", None, Unset], data) + + thread = _parse_thread(d.pop("thread", UNSET)) + + def _parse_forwarding(data: object) -> Union["MessageForwarding", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + forwarding_type_0 = MessageForwarding.from_dict(data) + + return forwarding_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageForwarding", None, Unset], data) + + forwarding = _parse_forwarding(d.pop("forwarding", UNSET)) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + message = cls( + entity_type=entity_type, + entity_id=entity_id, + content=content, + id=id, + chat_id=chat_id, + user_id=user_id, + created_at=created_at, + files=files, + buttons=buttons, + thread=thread, + forwarding=forwarding, + parent_message_id=parent_message_id, + ) + + message.additional_properties = d + return message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py new file mode 100644 index 0000000..e8a126a --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class MessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py new file mode 100644 index 0000000..21509d2 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py @@ -0,0 +1,104 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.message_files_item_file_type import MessageFilesItemFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageFilesItem") + + +@_attrs_define +class MessageFilesItem: + """ + Attributes: + id (Union[Unset, int]): + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, MessageFilesItemFileType]): + url (Union[Unset, str]): Размер файла в байтах, отображаемый пользователю + """ + + id: Union[Unset, int] = UNSET + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, MessageFilesItemFileType] = UNSET + url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if url is not UNSET: + field_dict["url"] = url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, MessageFilesItemFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = MessageFilesItemFileType(_file_type) + + url = d.pop("url", UNSET) + + message_files_item = cls( + id=id, + key=key, + name=name, + file_type=file_type, + url=url, + ) + + message_files_item.additional_properties = d + return message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py new file mode 100644 index 0000000..1e00e5b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class MessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py new file mode 100644 index 0000000..6ce981d --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py @@ -0,0 +1,153 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageForwarding") + + +@_attrs_define +class MessageForwarding: + """ + Attributes: + original_message_id (Union[Unset, int]): Идентификатор оригинального сообщения + original_chat_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + author_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + original_created_at (Union[Unset, int]): Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id (Union[None, Unset, int]): Идентификатор треда, в котором находится оригинальное сообщение. + Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому был создан тред, в + котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + original_thread_parent_chat_id (Union[None, Unset, int]): Идентификатор чата сообщения, к которому был создан + тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + """ + + original_message_id: Union[Unset, int] = UNSET + original_chat_id: Union[Unset, int] = UNSET + author_id: Union[Unset, int] = UNSET + original_created_at: Union[Unset, int] = UNSET + original_thread_id: Union[None, Unset, int] = UNSET + original_thread_message_id: Union[None, Unset, int] = UNSET + original_thread_parent_chat_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + original_message_id = self.original_message_id + + original_chat_id = self.original_chat_id + + author_id = self.author_id + + original_created_at = self.original_created_at + + original_thread_id: Union[None, Unset, int] + if isinstance(self.original_thread_id, Unset): + original_thread_id = UNSET + else: + original_thread_id = self.original_thread_id + + original_thread_message_id: Union[None, Unset, int] + if isinstance(self.original_thread_message_id, Unset): + original_thread_message_id = UNSET + else: + original_thread_message_id = self.original_thread_message_id + + original_thread_parent_chat_id: Union[None, Unset, int] + if isinstance(self.original_thread_parent_chat_id, Unset): + original_thread_parent_chat_id = UNSET + else: + original_thread_parent_chat_id = self.original_thread_parent_chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if original_message_id is not UNSET: + field_dict["original_message_id"] = original_message_id + if original_chat_id is not UNSET: + field_dict["original_chat_id"] = original_chat_id + if author_id is not UNSET: + field_dict["author_id"] = author_id + if original_created_at is not UNSET: + field_dict["original_created_at"] = original_created_at + if original_thread_id is not UNSET: + field_dict["original_thread_id"] = original_thread_id + if original_thread_message_id is not UNSET: + field_dict["original_thread_message_id"] = original_thread_message_id + if original_thread_parent_chat_id is not UNSET: + field_dict["original_thread_parent_chat_id"] = original_thread_parent_chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + original_message_id = d.pop("original_message_id", UNSET) + + original_chat_id = d.pop("original_chat_id", UNSET) + + author_id = d.pop("author_id", UNSET) + + original_created_at = d.pop("original_created_at", UNSET) + + def _parse_original_thread_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_id = _parse_original_thread_id(d.pop("original_thread_id", UNSET)) + + def _parse_original_thread_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_message_id = _parse_original_thread_message_id(d.pop("original_thread_message_id", UNSET)) + + def _parse_original_thread_parent_chat_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_parent_chat_id = _parse_original_thread_parent_chat_id( + d.pop("original_thread_parent_chat_id", UNSET) + ) + + message_forwarding = cls( + original_message_id=original_message_id, + original_chat_id=original_chat_id, + author_id=author_id, + original_created_at=original_created_at, + original_thread_id=original_thread_id, + original_thread_message_id=original_thread_message_id, + original_thread_parent_chat_id=original_thread_parent_chat_id, + ) + + message_forwarding.additional_properties = d + return message_forwarding + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py new file mode 100644 index 0000000..ddd18f0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageThread") + + +@_attrs_define +class MessageThread: + """ + Attributes: + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_thread = cls( + id=id, + chat_id=chat_id, + ) + + message_thread.additional_properties = d + return message_thread + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py new file mode 100644 index 0000000..c24e928 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py @@ -0,0 +1,59 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="NotFound") + + +@_attrs_define +class NotFound: + """Объект не найден + + Attributes: + detail (Union[Unset, str]): Описание ошибки Example: Страница не найдена.. + """ + + detail: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if detail is not UNSET: + field_dict["detail"] = detail + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + detail = d.pop("detail", UNSET) + + not_found = cls( + detail=detail, + ) + + not_found.additional_properties = d + return not_found + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py new file mode 100644 index 0000000..620f8dc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py @@ -0,0 +1,69 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMembersToChatsBody") + + +@_attrs_define +class PostMembersToChatsBody: + """ + Attributes: + member_ids (list[int]): Example: [186, 187]. + silent (Union[Unset, bool]): + """ + + member_ids: list[int] + silent: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + member_ids = self.member_ids + + silent = self.silent + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "member_ids": member_ids, + } + ) + if silent is not UNSET: + field_dict["silent"] = silent + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + member_ids = cast(list[int], d.pop("member_ids")) + + silent = d.pop("silent", UNSET) + + post_members_to_chats_body = cls( + member_ids=member_ids, + silent=silent, + ) + + post_members_to_chats_body.additional_properties = d + return post_members_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py new file mode 100644 index 0000000..fffa22a --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostMessageReactionsBody") + + +@_attrs_define +class PostMessageReactionsBody: + """ + Attributes: + code (str): Emoji в строковом формате для добавления реакции. + """ + + code: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "code": code, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + code = d.pop("code") + + post_message_reactions_body = cls( + code=code, + ) + + post_message_reactions_body.additional_properties = d + return post_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py new file mode 100644 index 0000000..50b0078 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse400") + + +@_attrs_define +class PostMessageReactionsResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_400 = cls( + error=error, + ) + + post_message_reactions_response_400.additional_properties = d + return post_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py new file mode 100644 index 0000000..cd52780 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse403") + + +@_attrs_define +class PostMessageReactionsResponse403: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_403 = cls( + error=error, + ) + + post_message_reactions_response_403.additional_properties = d + return post_message_reactions_response_403 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py new file mode 100644 index 0000000..1a26c89 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse404") + + +@_attrs_define +class PostMessageReactionsResponse404: + """ + Attributes: + error (Union[Unset, str]): Сообщение не найдено. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_404 = cls( + error=error, + ) + + post_message_reactions_response_404.additional_properties = d + return post_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py new file mode 100644 index 0000000..23040f4 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostTagsToChatsBody") + + +@_attrs_define +class PostTagsToChatsBody: + """ + Attributes: + group_tag_ids (list[int]): Example: [86, 18]. + """ + + group_tag_ids: list[int] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + group_tag_ids = self.group_tag_ids + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "group_tag_ids": group_tag_ids, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + group_tag_ids = cast(list[int], d.pop("group_tag_ids")) + + post_tags_to_chats_body = cls( + group_tag_ids=group_tag_ids, + ) + + post_tags_to_chats_body.additional_properties = d + return post_tags_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py new file mode 100644 index 0000000..1abee57 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_body_task import PostTasksBodyTask + + +T = TypeVar("T", bound="PostTasksBody") + + +@_attrs_define +class PostTasksBody: + """ + Attributes: + task (Union[Unset, PostTasksBodyTask]): + """ + + task: Union[Unset, "PostTasksBodyTask"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + task: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.task, Unset): + task = self.task.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if task is not UNSET: + field_dict["task"] = task + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_body_task import PostTasksBodyTask + + d = src_dict.copy() + _task = d.pop("task", UNSET) + task: Union[Unset, PostTasksBodyTask] + if isinstance(_task, Unset): + task = UNSET + else: + task = PostTasksBodyTask.from_dict(_task) + + post_tasks_body = cls( + task=task, + ) + + post_tasks_body.additional_properties = d + return post_tasks_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py new file mode 100644 index 0000000..f85bf85 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py @@ -0,0 +1,123 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem + + +T = TypeVar("T", bound="PostTasksBodyTask") + + +@_attrs_define +class PostTasksBodyTask: + """ + Attributes: + kind (str): Тип напоминания (call, meeting, reminder, event, email) + content (str): Описание напоминания + due_at (datetime.datetime): Срок выполнения напоминания (ISO-8601) + priority (Union[Unset, int]): Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей + custom_properties (Union[Unset, list['PostTasksBodyTaskCustomPropertiesItem']]): + """ + + kind: str + content: str + due_at: datetime.datetime + priority: Union[Unset, int] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["PostTasksBodyTaskCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind = self.kind + + content = self.content + + due_at = self.due_at.isoformat() + + priority = self.priority + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "content": content, + "due_at": due_at, + } + ) + if priority is not UNSET: + field_dict["priority"] = priority + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem + + d = src_dict.copy() + kind = d.pop("kind") + + content = d.pop("content") + + due_at = isoparse(d.pop("due_at")) + + priority = d.pop("priority", UNSET) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = PostTasksBodyTaskCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + post_tasks_body_task = cls( + kind=kind, + content=content, + due_at=due_at, + priority=priority, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + post_tasks_body_task.additional_properties = d + return post_tasks_body_task + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py new file mode 100644 index 0000000..279e511 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksBodyTaskCustomPropertiesItem") + + +@_attrs_define +class PostTasksBodyTaskCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + value (Union[Unset, str]): Значение поля + """ + + id: Union[Unset, int] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + value = d.pop("value", UNSET) + + post_tasks_body_task_custom_properties_item = cls( + id=id, + value=value, + ) + + post_tasks_body_task_custom_properties_item.additional_properties = d + return post_tasks_body_task_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py new file mode 100644 index 0000000..5dcd6b7 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_response_201_data import PostTasksResponse201Data + + +T = TypeVar("T", bound="PostTasksResponse201") + + +@_attrs_define +class PostTasksResponse201: + """ + Attributes: + data (Union[Unset, PostTasksResponse201Data]): + """ + + data: Union[Unset, "PostTasksResponse201Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_response_201_data import PostTasksResponse201Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, PostTasksResponse201Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = PostTasksResponse201Data.from_dict(_data) + + post_tasks_response_201 = cls( + data=data, + ) + + post_tasks_response_201.additional_properties = d + return post_tasks_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py new file mode 100644 index 0000000..b714c69 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py @@ -0,0 +1,177 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_response_201_data_custom_properties_item import ( + PostTasksResponse201DataCustomPropertiesItem, + ) + + +T = TypeVar("T", bound="PostTasksResponse201Data") + + +@_attrs_define +class PostTasksResponse201Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного напоминания + kind (Union[Unset, str]): Тип + content (Union[Unset, str]): Описание + due_at (Union[Unset, datetime.datetime]): Срок выполнения (ISO-8601) + priority (Union[Unset, int]): Приоритет + user_id (Union[Unset, int]): Идентификатор пользователя-создателя + status (Union[Unset, str]): Статус напоминания + created_at (Union[Unset, datetime.datetime]): Дата и время создания + performer_ids (Union[Unset, list[int]]): + custom_properties (Union[Unset, list['PostTasksResponse201DataCustomPropertiesItem']]): + """ + + id: Union[Unset, int] = UNSET + kind: Union[Unset, str] = UNSET + content: Union[Unset, str] = UNSET + due_at: Union[Unset, datetime.datetime] = UNSET + priority: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + status: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["PostTasksResponse201DataCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + kind = self.kind + + content = self.content + + due_at: Union[Unset, str] = UNSET + if not isinstance(self.due_at, Unset): + due_at = self.due_at.isoformat() + + priority = self.priority + + user_id = self.user_id + + status = self.status + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if kind is not UNSET: + field_dict["kind"] = kind + if content is not UNSET: + field_dict["content"] = content + if due_at is not UNSET: + field_dict["due_at"] = due_at + if priority is not UNSET: + field_dict["priority"] = priority + if user_id is not UNSET: + field_dict["user_id"] = user_id + if status is not UNSET: + field_dict["status"] = status + if created_at is not UNSET: + field_dict["created_at"] = created_at + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_response_201_data_custom_properties_item import ( + PostTasksResponse201DataCustomPropertiesItem, + ) + + d = src_dict.copy() + id = d.pop("id", UNSET) + + kind = d.pop("kind", UNSET) + + content = d.pop("content", UNSET) + + _due_at = d.pop("due_at", UNSET) + due_at: Union[Unset, datetime.datetime] + if isinstance(_due_at, Unset): + due_at = UNSET + else: + due_at = isoparse(_due_at) + + priority = d.pop("priority", UNSET) + + user_id = d.pop("user_id", UNSET) + + status = d.pop("status", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = PostTasksResponse201DataCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + post_tasks_response_201_data = cls( + id=id, + kind=kind, + content=content, + due_at=due_at, + priority=priority, + user_id=user_id, + status=status, + created_at=created_at, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + post_tasks_response_201_data.additional_properties = d + return post_tasks_response_201_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py new file mode 100644 index 0000000..1dc217e --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksResponse201DataCustomPropertiesItem") + + +@_attrs_define +class PostTasksResponse201DataCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + post_tasks_response_201_data_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + post_tasks_response_201_data_custom_properties_item.additional_properties = d + return post_tasks_response_201_data_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py new file mode 100644 index 0000000..e5ca651 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksResponse400") + + +@_attrs_define +class PostTasksResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_tasks_response_400 = cls( + error=error, + ) + + post_tasks_response_400.additional_properties = d + return post_tasks_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py new file mode 100644 index 0000000..24a5140 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py @@ -0,0 +1,72 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages import EditMessages + + +T = TypeVar("T", bound="PutMessagesIdBody") + + +@_attrs_define +class PutMessagesIdBody: + """ + Attributes: + message (Union[Unset, EditMessages]): Для получения сообщения вам необходимо знать его id и указать его в URL + запроса. + """ + + message: Union[Unset, "EditMessages"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages import EditMessages + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, EditMessages] + if isinstance(_message, Unset): + message = UNSET + else: + message = EditMessages.from_dict(_message) + + put_messages_id_body = cls( + message=message, + ) + + put_messages_id_body.additional_properties = d + return put_messages_id_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py new file mode 100644 index 0000000..5cb478f --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="PutMessagesIdResponse200") + + +@_attrs_define +class PutMessagesIdResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): Созданное сообщение + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + put_messages_id_response_200 = cls( + data=data, + ) + + put_messages_id_response_200.additional_properties = d + return put_messages_id_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py new file mode 100644 index 0000000..a34d4e0 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="PutStatusResponse201") + + +@_attrs_define +class PutStatusResponse201: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + put_status_response_201 = cls( + data=data, + ) + + put_status_response_201.additional_properties = d + return put_status_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py new file mode 100644 index 0000000..f3e1788 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py @@ -0,0 +1,91 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryChat") + + +@_attrs_define +class QueryChat: + """Собранный объект параметров создаваемой беседы или канала + + Attributes: + name (str): Название Example: 🤿 aqua. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, которые станут участниками Example: + [186, 187]. + channel (Union[Unset, bool]): Тип: беседа (по умолчанию, false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (по умолчанию, false) или открытый (true) + """ + + name: str + member_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + channel = self.channel + + public = self.public + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + query_chat = cls( + name=name, + member_ids=member_ids, + channel=channel, + public=public, + ) + + query_chat.additional_properties = d + return query_chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py new file mode 100644 index 0000000..f575b43 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryCommonMethods") + + +@_attrs_define +class QueryCommonMethods: + """получение списка актульных полей сущности. + + Attributes: + id (Union[Unset, int]): Название поля Example: 1. + name (Union[Unset, str]): Идентификатор поля Example: Дата рождения. + data_type (Union[Unset, str]): тип поля (string, number, date или link) Example: number. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + query_common_methods = cls( + id=id, + name=name, + data_type=data_type, + ) + + query_common_methods.additional_properties = d + return query_common_methods + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py new file mode 100644 index 0000000..885c9fc --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_status_status import QueryStatusStatus + + +T = TypeVar("T", bound="QueryStatus") + + +@_attrs_define +class QueryStatus: + """ + Attributes: + status (Union[Unset, QueryStatusStatus]): Собранный объект параметров нового статуса + """ + + status: Union[Unset, "QueryStatusStatus"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.status, Unset): + status = self.status.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if status is not UNSET: + field_dict["status"] = status + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_status_status import QueryStatusStatus + + d = src_dict.copy() + _status = d.pop("status", UNSET) + status: Union[Unset, QueryStatusStatus] + if isinstance(_status, Unset): + status = UNSET + else: + status = QueryStatusStatus.from_dict(_status) + + query_status = cls( + status=status, + ) + + query_status.additional_properties = d + return query_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py new file mode 100644 index 0000000..48858ea --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py @@ -0,0 +1,102 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryStatusStatus") + + +@_attrs_define +class QueryStatusStatus: + """Собранный объект параметров нового статуса + + Attributes: + emoji (str): Emoji символ статуса + title (str): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ + """ + + emoji: str + title: str + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "emoji": emoji, + "title": title, + } + ) + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji") + + title = d.pop("title") + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + query_status_status = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + query_status_status.additional_properties = d + return query_status_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py new file mode 100644 index 0000000..de28f69 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py @@ -0,0 +1,86 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Reaction") + + +@_attrs_define +class Reaction: + """ + Attributes: + user_id (Union[Unset, int]): Идентификатор пользователя, оставившего реакцию. + created_at (Union[Unset, datetime.datetime]): Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY- + MM-DDThh:mm:ss.sssZ. + code (Union[Unset, str]): Emoji символ реакции. + """ + + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + code: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if code is not UNSET: + field_dict["code"] = code + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + code = d.pop("code", UNSET) + + reaction = cls( + user_id=user_id, + created_at=created_at, + code=code, + ) + + reaction.additional_properties = d + return reaction + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py new file mode 100644 index 0000000..8997cfe --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py @@ -0,0 +1,101 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="StatusType0") + + +@_attrs_define +class StatusType0: + """Статус. Возвращается как null, если статус не установлен. + + Attributes: + emoji (Union[Unset, str]): Emoji символ статуса + title (Union[Unset, str]): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + """ + + emoji: Union[Unset, str] = UNSET + title: Union[Unset, str] = UNSET + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if emoji is not UNSET: + field_dict["emoji"] = emoji + if title is not UNSET: + field_dict["title"] = title + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji", UNSET) + + title = d.pop("title", UNSET) + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + status_type_0 = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + status_type_0.additional_properties = d + return status_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py new file mode 100644 index 0000000..6504540 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Tag") + + +@_attrs_define +class Tag: + """Для получения тега вам необходимо знать его id и указать его в URL запроса. + + Attributes: + id (Union[Unset, int]): Идентификатор тега + name (Union[Unset, str]): Название тега + users_count (Union[Unset, int]): Количество сотрудников, которые имеют этот тег + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + users_count: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + users_count = self.users_count + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if users_count is not UNSET: + field_dict["users_count"] = users_count + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + users_count = d.pop("users_count", UNSET) + + tag = cls( + id=id, + name=name, + users_count=users_count, + ) + + tag.additional_properties = d + return tag + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed new file mode 100644 index 0000000..1aad327 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py new file mode 100644 index 0000000..b9ed58b --- /dev/null +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py @@ -0,0 +1,46 @@ +"""Contains some shared types for properties""" + +from collections.abc import MutableMapping +from http import HTTPStatus +from typing import BinaryIO, Generic, Literal, Optional, TypeVar + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: Optional[str] = None + mime_type: Optional[str] = None + + def to_tuple(self) -> FileJsonType: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: Optional[T] + + +__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/pachca-api-open-api-3-0-client/pyproject.toml b/pachca-api-open-api-3-0-client/pyproject.toml new file mode 100644 index 0000000..29f8de8 --- /dev/null +++ b/pachca-api-open-api-3-0-client/pyproject.toml @@ -0,0 +1,27 @@ +[tool.poetry] +name = "pachca-api-open-api-3-0-client" +version = "3.0.3" +description = "A client library for accessing PachcaAPI - OpenAPI 3.0" +authors = [] +readme = "README.md" +packages = [ + {include = "pachca_api_open_api_3_0_client"}, +] +include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] + + +[tool.poetry.dependencies] +python = "^3.9" +httpx = ">=0.20.0,<0.28.0" +attrs = ">=21.3.0" +python-dateutil = "^2.8.0" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["F", "I", "UP"] diff --git a/pachca.py b/pachca.py new file mode 100644 index 0000000..5e57da0 --- /dev/null +++ b/pachca.py @@ -0,0 +1,26 @@ +import asyncio + +from pachca_api.pachca_api_open_api_3_0_client.client import AuthenticatedClient +from pachca_api.pachca_api_open_api_3_0_client.api.chats_and_channels.create_chat import asyncio as as2 +from pachca_api.pachca_api_open_api_3_0_client.api.employees.get_employees import asyncio as as1 +from pachca_api.pachca_api_open_api_3_0_client.models.create_chat_body import CreateChatBody +from pachca_api.pachca_api_open_api_3_0_client.models.query_chat import QueryChat + +client = AuthenticatedClient( + base_url='https://api.pachca.com/api/shared/v1', + token='35KekGygDNiFwtPpqUe44CaEZ_EVL17ycYRJrMnvHOs' +) + +query_chat = QueryChat(name='water') +chat_body = CreateChatBody(chat=query_chat) + +async def main(): + task1 = asyncio.create_task(as1(client=client))#, id=511008)) + task2 = asyncio.create_task(as2(client=client, body=chat_body)) + + print(await task1) + print('#'*30) + print(await task2) + +asyncio.run(main()) + diff --git a/pachca_api/.gitignore b/pachca_api/.gitignore new file mode 100644 index 0000000..79a2c3d --- /dev/null +++ b/pachca_api/.gitignore @@ -0,0 +1,23 @@ +__pycache__/ +build/ +dist/ +*.egg-info/ +.pytest_cache/ + +# pyenv +.python-version + +# Environments +.env +.venv + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# JetBrains +.idea/ + +/coverage.xml +/.coverage diff --git a/pachca_api/README.md b/pachca_api/README.md new file mode 100644 index 0000000..3bb71ab --- /dev/null +++ b/pachca_api/README.md @@ -0,0 +1,124 @@ +# pachca-api-open-api-3-0-client +A client library for accessing PachcaAPI - OpenAPI 3.0 + +## Usage +First, create a client: + +```python +from pachca_api_open_api_3_0_client import Client + +client = Client(base_url="https://api.example.com") +``` + +If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: + +```python +from pachca_api_open_api_3_0_client import AuthenticatedClient + +client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") +``` + +Now call your endpoint and use your models: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +with client as client: + my_data: MyDataModel = get_my_data_model.sync(client=client) + # or if you need more info (e.g. status_code) + response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) +``` + +Or do the same thing with an async version: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +async with client as client: + my_data: MyDataModel = await get_my_data_model.asyncio(client=client) + response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) +``` + +By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl="/path/to/certificate_bundle.pem", +) +``` + +You can also disable certificate validation altogether, but beware that **this is a security risk**. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl=False +) +``` + +Things to know: +1. Every path/method combo becomes a Python module with four functions: + 1. `sync`: Blocking request that returns parsed data (if successful) or `None` + 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. + 1. `asyncio`: Like `sync` but async instead of blocking + 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking + +1. All path/query params, and bodies become method arguments. +1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) +1. Any endpoint which did not have a tag will be in `pachca_api_open_api_3_0_client.api.default` + +## Advanced customizations + +There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): + +```python +from pachca_api_open_api_3_0_client import Client + +def log_request(request): + print(f"Request event hook: {request.method} {request.url} - Waiting for response") + +def log_response(response): + request = response.request + print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") + +client = Client( + base_url="https://api.example.com", + httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, +) + +# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() +``` + +You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): + +```python +import httpx +from pachca_api_open_api_3_0_client import Client + +client = Client( + base_url="https://api.example.com", +) +# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. +client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) +``` + +## Building / publishing this package +This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: +1. Update the metadata in pyproject.toml (e.g. authors, version) +1. If you're using a private repository, configure it with Poetry + 1. `poetry config repositories. ` + 1. `poetry config http-basic. ` +1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` + +If you want to install this client into another project without publishing it (e.g. for development) then: +1. If that project **is using Poetry**, you can simply do `poetry add ` from that project +1. If that project is not using Poetry: + 1. Build a wheel with `poetry build -f wheel` + 1. Install that wheel from the other project `pip install ` diff --git a/pachca_api/pachca_api_open_api_3_0_client/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/__init__.py new file mode 100644 index 0000000..3a6c9f0 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/__init__.py @@ -0,0 +1,8 @@ +"""A client library for accessing PachcaAPI - OpenAPI 3.0""" + +from .client import AuthenticatedClient, Client + +__all__ = ( + "AuthenticatedClient", + "Client", +) diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/__init__.py new file mode 100644 index 0000000..81f9fa2 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/__init__.py @@ -0,0 +1 @@ +"""Contains methods for accessing the API""" diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py new file mode 100644 index 0000000..40b8fc3 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -0,0 +1,187 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.create_chat_body import CreateChatBody +from ...models.create_chat_response_201 import CreateChatResponse201 +from ...models.create_chat_response_400 import CreateChatResponse400 +from ...models.create_chat_response_404 import CreateChatResponse404 +from ...models.create_chat_response_422 import CreateChatResponse422 +from ...types import Response + + +def _get_kwargs( + *, + body: CreateChatBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/chats", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + body: CreateChatBody, +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py new file mode 100644 index 0000000..b7edc44 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -0,0 +1,167 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_chat_response_200 import GetChatResponse200 +from ...models.get_chat_response_404 import GetChatResponse404 +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/chats/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatResponse200, GetChatResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatResponse200, GetChatResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py new file mode 100644 index 0000000..0cbd54d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -0,0 +1,277 @@ +import datetime +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_chats_availability import GetChatsAvailability +from ...models.get_chats_response_200 import GetChatsResponse200 +from ...models.get_chats_response_400 import GetChatsResponse400 +from ...models.get_chats_response_404 import GetChatsResponse404 +from ...models.get_chats_response_422 import GetChatsResponse422 +from ...models.get_chats_sortid import GetChatsSortid +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + + params["sort[id]"] = json_sortid + + params["per"] = per + + params["page"] = page + + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + + params["availability"] = json_availability + + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params["last_message_at_after"] = json_last_message_at_after + + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params["last_message_at_before"] = json_last_message_at_before + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/chats", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + + return response_422 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + + kwargs = _get_kwargs( + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + + return sync_detailed( + client=client, + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + + kwargs = _get_kwargs( + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + + return ( + await asyncio_detailed( + client=client, + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/comments/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/comments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/pachca_api/pachca_api_open_api_3_0_client/api/comments/create_thread.py new file mode 100644 index 0000000..775463d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -0,0 +1,172 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.create_thread_response_200 import CreateThreadResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/thread", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py new file mode 100644 index 0000000..6db7fd3 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -0,0 +1,175 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from ...types import UNSET, Response + + +def _get_kwargs( + *, + entity_type: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["entity_type"] = entity_type + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/custom_properties", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + + kwargs = _get_kwargs( + entity_type=entity_type, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + + return sync_detailed( + client=client, + entity_type=entity_type, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + + kwargs = _get_kwargs( + entity_type=entity_type, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + entity_type: str, +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + + return ( + await asyncio_detailed( + client=client, + entity_type=entity_type, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py new file mode 100644 index 0000000..9d9e1d5 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py @@ -0,0 +1,106 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.direct_response import DirectResponse +from ...types import Response + + +def _get_kwargs( + *, + body: DirectResponse, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/direct_url", + } + + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: DirectResponse, +) -> Response[Any]: + """Получение URL для загрузки + + Отправляет запрос для получения URL для безопасной загрузки файла. + + Args: + body (DirectResponse): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: DirectResponse, +) -> Response[Any]: + """Получение URL для загрузки + + Отправляет запрос для получения URL для безопасной загрузки файла. + + Args: + body (DirectResponse): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py new file mode 100644 index 0000000..eb8174d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -0,0 +1,130 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.file_response import FileResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/uploads", + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[FileResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[FileResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[FileResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/employees/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/employees/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employee.py new file mode 100644 index 0000000..ead0595 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -0,0 +1,167 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_employee_response_200 import GetEmployeeResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/users/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetEmployeeResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetEmployeeResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employees.py new file mode 100644 index 0000000..2602547 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_employees_response_200 import GetEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params["query"] = query + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[GetEmployeesResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + query=query, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + + return sync_detailed( + client=client, + per=per, + page=page, + query=query, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + query=query, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + + return ( + await asyncio_detailed( + client=client, + per=per, + page=page, + query=query, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/messages/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/messages/create_message.py b/pachca_api/pachca_api_open_api_3_0_client/api/messages/create_message.py new file mode 100644 index 0000000..c370a96 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -0,0 +1,231 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.create_message_body import CreateMessageBody +from ...models.create_message_response_201 import CreateMessageResponse201 +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + *, + body: CreateMessageBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/messages", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + response_404.append(componentsschemas_errors_item) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + body: CreateMessageBody, +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/pachca_api/pachca_api_open_api_3_0_client/api/messages/get_list_message.py new file mode 100644 index 0000000..074c626 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -0,0 +1,226 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_list_message_response_200 import GetListMessageResponse200 +from ...models.not_found import NotFound +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["chat_id"] = chat_id + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/messages", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetListMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + chat_id=chat_id, + per=per, + page=page, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + + return sync_detailed( + client=client, + chat_id=chat_id, + per=per, + page=page, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + chat_id=chat_id, + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + client=client, + chat_id=chat_id, + per=per, + page=page, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/messages/get_message.py b/pachca_api/pachca_api_open_api_3_0_client/api/messages/get_message.py new file mode 100644 index 0000000..6926078 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -0,0 +1,171 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_message_response_200 import GetMessageResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py b/pachca_api/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py new file mode 100644 index 0000000..f58d88e --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py @@ -0,0 +1,200 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.put_messages_id_body import PutMessagesIdBody +from ...models.put_messages_id_response_200 import PutMessagesIdResponse200 +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: PutMessagesIdBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": f"/messages/{id}", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = PutMessagesIdResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PutMessagesIdResponse200, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PutMessagesIdBody, +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (PutMessagesIdBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PutMessagesIdResponse200, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py new file mode 100644 index 0000000..8d768e3 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -0,0 +1,191 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from ...types import UNSET, Response + + +def _get_kwargs( + id: str, + *, + code: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["code"] = code + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/messages/{id}/reactions", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + code=code, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + + return sync_detailed( + id=id, + client=client, + code=code, + ).parsed + + +async def asyncio_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + code=code, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: str, + *, + client: Union[AuthenticatedClient, Client], + code: str, +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (str): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + code=code, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py new file mode 100644 index 0000000..e32a17a --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_message_reactions_body import GetMessageReactionsBody +from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: GetMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: GetMessageReactionsBody, +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py new file mode 100644 index 0000000..5be7653 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -0,0 +1,214 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_message_reactions_body import PostMessageReactionsBody +from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from ...types import Response + + +def _get_kwargs( + id: str, + *, + body: PostMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: str, + *, + client: Union[AuthenticatedClient, Client], + body: PostMessageReactionsBody, +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (str): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/reminders/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/reminders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py b/pachca_api/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py new file mode 100644 index 0000000..d300687 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py @@ -0,0 +1,193 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.post_tasks_body import PostTasksBody +from ...models.post_tasks_response_201 import PostTasksResponse201 +from ...models.post_tasks_response_400 import PostTasksResponse400 +from ...types import Response + + +def _get_kwargs( + *, + body: PostTasksBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tasks", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = PostTasksResponse400.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PostTasksResponse201, PostTasksResponse400]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PostTasksResponse201, PostTasksResponse400] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[PostTasksResponse201, PostTasksResponse400]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + body: PostTasksBody, +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (PostTasksBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[PostTasksResponse201, PostTasksResponse400] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/status/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/status/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/status/del_status.py b/pachca_api/pachca_api_open_api_3_0_client/api/status/del_status.py new file mode 100644 index 0000000..1b7bdb9 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/status/del_status.py @@ -0,0 +1,83 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/status/get_status.py b/pachca_api/pachca_api_open_api_3_0_client/api/status/get_status.py new file mode 100644 index 0000000..c2cf45c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -0,0 +1,134 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_status_response_200 import GetStatusResponse200 +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + + return response_200 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[GetStatusResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetStatusResponse200] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetStatusResponse200] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/status/put_status.py b/pachca_api/pachca_api_open_api_3_0_client/api/status/put_status.py new file mode 100644 index 0000000..485bf89 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.put_status_response_201 import PutStatusResponse201 +from ...models.query_status import QueryStatus +from ...types import Response + + +def _get_kwargs( + *, + body: QueryStatus, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/profile/status", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, PutStatusResponse201]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, PutStatusResponse201]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + body: QueryStatus, +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/tags/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/tags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tag.py new file mode 100644 index 0000000..6359a6e --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -0,0 +1,163 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_tag_response_200 import GetTagResponse200 +from ...models.get_tag_response_404 import GetTagResponse404 +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagResponse200, GetTagResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagResponse200, GetTagResponse404]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags.py new file mode 100644 index 0000000..2b8afca --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -0,0 +1,186 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.get_tags_response_200 import GetTagsResponse200 +from ...models.get_tags_response_400 import GetTagsResponse400 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/group_tags", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + + return sync_detailed( + client=client, + per=per, + page=page, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + + kwargs = _get_kwargs( + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + + return ( + await asyncio_detailed( + client=client, + per=per, + page=page, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py new file mode 100644 index 0000000..98bda74 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -0,0 +1,199 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.bad_request import BadRequest +from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: int, + *, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}/users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetTagsEmployeesResponse200]] + """ + + kwargs = _get_kwargs( + id=id, + per=per, + page=page, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + + return sync_detailed( + id=id, + client=client, + per=per, + page=page, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetTagsEmployeesResponse200]] + """ + + kwargs = _get_kwargs( + id=id, + per=per, + page=page, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + per=per, + page=page, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py new file mode 100644 index 0000000..4049584 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py @@ -0,0 +1,175 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...types import Response + + +def _get_kwargs( + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/chats/{id}/leave", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py new file mode 100644 index 0000000..18f997d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.post_members_to_chats_body import PostMembersToChatsBody +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: PostMembersToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/members", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostMembersToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py new file mode 100644 index 0000000..7e6be16 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.errors_code import ErrorsCode +from ...models.post_tags_to_chats_body import PostTagsToChatsBody +from ...types import Response + + +def _get_kwargs( + id: int, + *, + body: PostTagsToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/group_tags", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Response[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: int, + *, + client: Union[AuthenticatedClient, Client], + body: PostTagsToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/pachca_api/pachca_api_open_api_3_0_client/client.py b/pachca_api/pachca_api_open_api_3_0_client/client.py new file mode 100644 index 0000000..e80446f --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/client.py @@ -0,0 +1,268 @@ +import ssl +from typing import Any, Optional, Union + +import httpx +from attrs import define, evolve, field + + +@define +class Client: + """A class for keeping track of data related to the API + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/pachca_api/pachca_api_open_api_3_0_client/errors.py b/pachca_api/pachca_api_open_api_3_0_client/errors.py new file mode 100644 index 0000000..5f92e76 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/errors.py @@ -0,0 +1,16 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/__init__.py b/pachca_api/pachca_api_open_api_3_0_client/models/__init__.py new file mode 100644 index 0000000..bf2d6c3 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/__init__.py @@ -0,0 +1,189 @@ +"""Contains all the data models used in inputs/outputs""" + +from .bad_request import BadRequest +from .base_employee import BaseEmployee +from .base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem +from .button import Button +from .chat import Chat +from .create_chat_body import CreateChatBody +from .create_chat_response_201 import CreateChatResponse201 +from .create_chat_response_400 import CreateChatResponse400 +from .create_chat_response_404 import CreateChatResponse404 +from .create_chat_response_422 import CreateChatResponse422 +from .create_message import CreateMessage +from .create_message_body import CreateMessageBody +from .create_message_entity_type import CreateMessageEntityType +from .create_message_files_item import CreateMessageFilesItem +from .create_message_files_item_file_type import CreateMessageFilesItemFileType +from .create_message_response_201 import CreateMessageResponse201 +from .create_thread_response_200 import CreateThreadResponse200 +from .create_thread_response_200_data import CreateThreadResponse200Data +from .delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from .delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem +from .delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, +) +from .delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem +from .delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, +) +from .direct_response import DirectResponse +from .edit_messages import EditMessages +from .edit_messages_buttons_item_item import EditMessagesButtonsItemItem +from .edit_messages_files import EditMessagesFiles +from .edit_messages_files_file_type import EditMessagesFilesFileType +from .employee import Employee +from .error import Error +from .error_payload import ErrorPayload +from .errors_code import ErrorsCode +from .errors_code_payload import ErrorsCodePayload +from .file_response import FileResponse +from .get_chat_response_200 import GetChatResponse200 +from .get_chat_response_404 import GetChatResponse404 +from .get_chats_availability import GetChatsAvailability +from .get_chats_response_200 import GetChatsResponse200 +from .get_chats_response_400 import GetChatsResponse400 +from .get_chats_response_404 import GetChatsResponse404 +from .get_chats_response_422 import GetChatsResponse422 +from .get_chats_sortid import GetChatsSortid +from .get_common_methods_response_200 import GetCommonMethodsResponse200 +from .get_employee_response_200 import GetEmployeeResponse200 +from .get_employees_response_200 import GetEmployeesResponse200 +from .get_list_message_response_200 import GetListMessageResponse200 +from .get_message_reactions_body import GetMessageReactionsBody +from .get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .get_message_response_200 import GetMessageResponse200 +from .get_status_response_200 import GetStatusResponse200 +from .get_tag_response_200 import GetTagResponse200 +from .get_tag_response_404 import GetTagResponse404 +from .get_tag_response_404_errors_item import GetTagResponse404ErrorsItem +from .get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload +from .get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .get_tags_response_200 import GetTagsResponse200 +from .get_tags_response_400 import GetTagsResponse400 +from .get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem +from .get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload +from .message import Message +from .message_entity_type import MessageEntityType +from .message_files_item import MessageFilesItem +from .message_files_item_file_type import MessageFilesItemFileType +from .message_forwarding import MessageForwarding +from .message_thread import MessageThread +from .not_found import NotFound +from .post_members_to_chats_body import PostMembersToChatsBody +from .post_message_reactions_body import PostMessageReactionsBody +from .post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .post_tags_to_chats_body import PostTagsToChatsBody +from .post_tasks_body import PostTasksBody +from .post_tasks_body_task import PostTasksBodyTask +from .post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem +from .post_tasks_response_201 import PostTasksResponse201 +from .post_tasks_response_201_data import PostTasksResponse201Data +from .post_tasks_response_201_data_custom_properties_item import PostTasksResponse201DataCustomPropertiesItem +from .post_tasks_response_400 import PostTasksResponse400 +from .put_messages_id_body import PutMessagesIdBody +from .put_messages_id_response_200 import PutMessagesIdResponse200 +from .put_status_response_201 import PutStatusResponse201 +from .query_chat import QueryChat +from .query_common_methods import QueryCommonMethods +from .query_status import QueryStatus +from .query_status_status import QueryStatusStatus +from .reaction import Reaction +from .status_type_0 import StatusType0 +from .tag import Tag + +__all__ = ( + "BadRequest", + "BaseEmployee", + "BaseEmployeeCustomPropertiesItem", + "Button", + "Chat", + "CreateChatBody", + "CreateChatResponse201", + "CreateChatResponse400", + "CreateChatResponse404", + "CreateChatResponse422", + "CreateMessage", + "CreateMessageBody", + "CreateMessageEntityType", + "CreateMessageFilesItem", + "CreateMessageFilesItemFileType", + "CreateMessageResponse201", + "CreateThreadResponse200", + "CreateThreadResponse200Data", + "DeleteMessageReactionsResponse400", + "DeleteMessageReactionsResponse400ErrorsItem", + "DeleteMessageReactionsResponse400ErrorsItemPayload", + "DeleteMessageReactionsResponse404", + "DeleteMessageReactionsResponse404ErrorsItem", + "DeleteMessageReactionsResponse404ErrorsItemPayload", + "DirectResponse", + "EditMessages", + "EditMessagesButtonsItemItem", + "EditMessagesFiles", + "EditMessagesFilesFileType", + "Employee", + "Error", + "ErrorPayload", + "ErrorsCode", + "ErrorsCodePayload", + "FileResponse", + "GetChatResponse200", + "GetChatResponse404", + "GetChatsAvailability", + "GetChatsResponse200", + "GetChatsResponse400", + "GetChatsResponse404", + "GetChatsResponse422", + "GetChatsSortid", + "GetCommonMethodsResponse200", + "GetEmployeeResponse200", + "GetEmployeesResponse200", + "GetListMessageResponse200", + "GetMessageReactionsBody", + "GetMessageReactionsResponse200", + "GetMessageResponse200", + "GetStatusResponse200", + "GetTagResponse200", + "GetTagResponse404", + "GetTagResponse404ErrorsItem", + "GetTagResponse404ErrorsItemPayload", + "GetTagsEmployeesResponse200", + "GetTagsResponse200", + "GetTagsResponse400", + "GetTagsResponse400ErrorsItem", + "GetTagsResponse400ErrorsItemPayload", + "Message", + "MessageEntityType", + "MessageFilesItem", + "MessageFilesItemFileType", + "MessageForwarding", + "MessageThread", + "NotFound", + "PostMembersToChatsBody", + "PostMessageReactionsBody", + "PostMessageReactionsResponse400", + "PostMessageReactionsResponse403", + "PostMessageReactionsResponse404", + "PostTagsToChatsBody", + "PostTasksBody", + "PostTasksBodyTask", + "PostTasksBodyTaskCustomPropertiesItem", + "PostTasksResponse201", + "PostTasksResponse201Data", + "PostTasksResponse201DataCustomPropertiesItem", + "PostTasksResponse400", + "PutMessagesIdBody", + "PutMessagesIdResponse200", + "PutStatusResponse201", + "QueryChat", + "QueryCommonMethods", + "QueryStatus", + "QueryStatusStatus", + "Reaction", + "StatusType0", + "Tag", +) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/bad_request.py b/pachca_api/pachca_api_open_api_3_0_client/models/bad_request.py new file mode 100644 index 0000000..17dd6ed --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/bad_request.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BadRequest") + + +@_attrs_define +class BadRequest: + """ + Attributes: + error (Union[Unset, str]): + message (Union[Unset, str]): + """ + + error: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + message = d.pop("message", UNSET) + + bad_request = cls( + error=error, + message=message, + ) + + bad_request.additional_properties = d + return bad_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/base_employee.py b/pachca_api/pachca_api_open_api_3_0_client/models/base_employee.py new file mode 100644 index 0000000..b6a0314 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/base_employee.py @@ -0,0 +1,186 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + +T = TypeVar("T", bound="BaseEmployee") + + +@_attrs_define +class BaseEmployee: + """Базовый класс сотрудника. + + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + base_employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + ) + + base_employee.additional_properties = d + return base_employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py new file mode 100644 index 0000000..bee25c8 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BaseEmployeeCustomPropertiesItem") + + +@_attrs_define +class BaseEmployeeCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + base_employee_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + base_employee_custom_properties_item.additional_properties = d + return base_employee_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/button.py b/pachca_api/pachca_api_open_api_3_0_client/models/button.py new file mode 100644 index 0000000..64ea323 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/button.py @@ -0,0 +1,78 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Button") + + +@_attrs_define +class Button: + """ + Attributes: + text (str): + url (Union[Unset, str]): + data (Union[Unset, str]): + """ + + text: str + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + } + ) + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text") + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + button = cls( + text=text, + url=url, + data=data, + ) + + button.additional_properties = d + return button + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/chat.py b/pachca_api/pachca_api_open_api_3_0_client/models/chat.py new file mode 100644 index 0000000..7ef2560 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/chat.py @@ -0,0 +1,162 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Chat") + + +@_attrs_define +class Chat: + """Беседа или канал + + Attributes: + id (Union[Unset, int]): Идентификатор беседы или канала Example: 334. + name (Union[Unset, str]): Название Example: 🤿 aqua. + owner_id (Union[Unset, int]): Идентификатор пользователя, создавшего беседу или канал Example: 185. + created_at (Union[Unset, datetime.datetime]): Дата и время создания беседы или канала (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:56:53.000Z. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, участников Example: [185, 186, 187]. + group_tag_ids (Union[Unset, list[int]]): Массив идентификаторов тегов, участников + channel (Union[Unset, bool]): Тип: беседа (false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (false) или открытый (true) + last_message_at (Union[Unset, datetime.datetime]): Дата и время создания последнего сообщения в беседе/канале + (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:58:13.000Z. + meet_room_url (Union[Unset, str]): Ссылка на Видеочат Example: https://meet.pachca.com/aqua-94bb21b5. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + owner_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + member_ids: Union[Unset, list[int]] = UNSET + group_tag_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + last_message_at: Union[Unset, datetime.datetime] = UNSET + meet_room_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + owner_id = self.owner_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + group_tag_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.group_tag_ids, Unset): + group_tag_ids = self.group_tag_ids + + channel = self.channel + + public = self.public + + last_message_at: Union[Unset, str] = UNSET + if not isinstance(self.last_message_at, Unset): + last_message_at = self.last_message_at.isoformat() + + meet_room_url = self.meet_room_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if owner_id is not UNSET: + field_dict["owner_id"] = owner_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if group_tag_ids is not UNSET: + field_dict["group_tag_ids"] = group_tag_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + if last_message_at is not UNSET: + field_dict["last_message_at"] = last_message_at + if meet_room_url is not UNSET: + field_dict["meet_room_url"] = meet_room_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + owner_id = d.pop("owner_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + group_tag_ids = cast(list[int], d.pop("group_tag_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + _last_message_at = d.pop("last_message_at", UNSET) + last_message_at: Union[Unset, datetime.datetime] + if isinstance(_last_message_at, Unset): + last_message_at = UNSET + else: + last_message_at = isoparse(_last_message_at) + + meet_room_url = d.pop("meet_room_url", UNSET) + + chat = cls( + id=id, + name=name, + owner_id=owner_id, + created_at=created_at, + member_ids=member_ids, + group_tag_ids=group_tag_ids, + channel=channel, + public=public, + last_message_at=last_message_at, + meet_room_url=meet_room_url, + ) + + chat.additional_properties = d + return chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_body.py new file mode 100644 index 0000000..8b9e361 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_chat import QueryChat + + +T = TypeVar("T", bound="CreateChatBody") + + +@_attrs_define +class CreateChatBody: + """ + Attributes: + chat (Union[Unset, QueryChat]): Собранный объект параметров создаваемой беседы или канала + """ + + chat: Union[Unset, "QueryChat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + chat: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.chat, Unset): + chat = self.chat.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if chat is not UNSET: + field_dict["chat"] = chat + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_chat import QueryChat + + d = src_dict.copy() + _chat = d.pop("chat", UNSET) + chat: Union[Unset, QueryChat] + if isinstance(_chat, Unset): + chat = UNSET + else: + chat = QueryChat.from_dict(_chat) + + create_chat_body = cls( + chat=chat, + ) + + create_chat_body.additional_properties = d + return create_chat_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_201.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_201.py new file mode 100644 index 0000000..3a928ef --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="CreateChatResponse201") + + +@_attrs_define +class CreateChatResponse201: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + create_chat_response_201 = cls( + data=data, + ) + + create_chat_response_201.additional_properties = d + return create_chat_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_400.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_400.py new file mode 100644 index 0000000..1d7fd30 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse400") + + +@_attrs_define +class CreateChatResponse400: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_400 = cls( + errors=errors, + ) + + create_chat_response_400.additional_properties = d + return create_chat_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_404.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_404.py new file mode 100644 index 0000000..3de2654 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse404") + + +@_attrs_define +class CreateChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_404 = cls( + errors=errors, + ) + + create_chat_response_404.additional_properties = d + return create_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_422.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_422.py new file mode 100644 index 0000000..c917758 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_chat_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse422") + + +@_attrs_define +class CreateChatResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_422 = cls( + errors=errors, + ) + + create_chat_response_422.additional_properties = d + return create_chat_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_message.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_message.py new file mode 100644 index 0000000..63e52de --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_message.py @@ -0,0 +1,178 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_entity_type import CreateMessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + +T = TypeVar("T", bound="CreateMessage") + + +@_attrs_define +class CreateMessage: + """ + Attributes: + entity_id (int): + content (str): + entity_type (Union[Unset, CreateMessageEntityType]): Default: CreateMessageEntityType.DISCUSSION. + files (Union[Unset, list['CreateMessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + parent_message_id (Union[None, Unset, int]): + skip_invite_mentions (Union[Unset, bool]): Default: False. + link_preview (Union[Unset, bool]): Default: False. + """ + + entity_id: int + content: str + entity_type: Union[Unset, CreateMessageEntityType] = CreateMessageEntityType.DISCUSSION + files: Union[Unset, list["CreateMessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + skip_invite_mentions: Union[Unset, bool] = False + link_preview: Union[Unset, bool] = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + content = self.content + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + skip_invite_mentions = self.skip_invite_mentions + + link_preview = self.link_preview + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "content": content, + } + ) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + if skip_invite_mentions is not UNSET: + field_dict["skip_invite_mentions"] = skip_invite_mentions + if link_preview is not UNSET: + field_dict["link_preview"] = link_preview + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + d = src_dict.copy() + entity_id = d.pop("entity_id") + + content = d.pop("content") + + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, CreateMessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = CreateMessageEntityType(_entity_type) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = CreateMessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + skip_invite_mentions = d.pop("skip_invite_mentions", UNSET) + + link_preview = d.pop("link_preview", UNSET) + + create_message = cls( + entity_id=entity_id, + content=content, + entity_type=entity_type, + files=files, + buttons=buttons, + parent_message_id=parent_message_id, + skip_invite_mentions=skip_invite_mentions, + link_preview=link_preview, + ) + + create_message.additional_properties = d + return create_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_message_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_body.py new file mode 100644 index 0000000..a8960fe --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_message import CreateMessage + + +T = TypeVar("T", bound="CreateMessageBody") + + +@_attrs_define +class CreateMessageBody: + """ + Attributes: + message (Union[Unset, CreateMessage]): + """ + + message: Union[Unset, "CreateMessage"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_message import CreateMessage + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, CreateMessage] + if isinstance(_message, Unset): + message = UNSET + else: + message = CreateMessage.from_dict(_message) + + create_message_body = cls( + message=message, + ) + + create_message_body.additional_properties = d + return create_message_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_message_entity_type.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_entity_type.py new file mode 100644 index 0000000..067c6f4 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class CreateMessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item.py new file mode 100644 index 0000000..a7c8ee3 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item.py @@ -0,0 +1,84 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_files_item_file_type import CreateMessageFilesItemFileType + +T = TypeVar("T", bound="CreateMessageFilesItem") + + +@_attrs_define +class CreateMessageFilesItem: + """ + Attributes: + key (str): + name (str): + file_type (CreateMessageFilesItemFileType): + size (int): + """ + + key: str + name: str + file_type: CreateMessageFilesItemFileType + size: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "key": key, + "name": name, + "file_type": file_type, + "size": size, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key") + + name = d.pop("name") + + file_type = CreateMessageFilesItemFileType(d.pop("file_type")) + + size = d.pop("size") + + create_message_files_item = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + create_message_files_item.additional_properties = d + return create_message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py new file mode 100644 index 0000000..89889f9 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CreateMessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_message_response_201.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_response_201.py new file mode 100644 index 0000000..b016d4c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_message_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="CreateMessageResponse201") + + +@_attrs_define +class CreateMessageResponse201: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + create_message_response_201 = cls( + data=data, + ) + + create_message_response_201.additional_properties = d + return create_message_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200.py new file mode 100644 index 0000000..15fd0b4 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + +T = TypeVar("T", bound="CreateThreadResponse200") + + +@_attrs_define +class CreateThreadResponse200: + """ + Attributes: + data (Union[Unset, CreateThreadResponse200Data]): + """ + + data: Union[Unset, "CreateThreadResponse200Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, CreateThreadResponse200Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = CreateThreadResponse200Data.from_dict(_data) + + create_thread_response_200 = cls( + data=data, + ) + + create_thread_response_200.additional_properties = d + return create_thread_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py b/pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py new file mode 100644 index 0000000..93b7457 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py @@ -0,0 +1,104 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateThreadResponse200Data") + + +@_attrs_define +class CreateThreadResponse200Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного треда. + chat_id (Union[Unset, int]): Идентификатор чата треда. + message_id (Union[Unset, int]): Идентификатор сообщения, к которому был создан тред. + message_chat_id (Union[Unset, int]): Идентификатор чата сообщения. + updated_at (Union[Unset, datetime.datetime]): Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + message_id: Union[Unset, int] = UNSET + message_chat_id: Union[Unset, int] = UNSET + updated_at: Union[Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + message_id = self.message_id + + message_chat_id = self.message_chat_id + + updated_at: Union[Unset, str] = UNSET + if not isinstance(self.updated_at, Unset): + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if message_id is not UNSET: + field_dict["message_id"] = message_id + if message_chat_id is not UNSET: + field_dict["message_chat_id"] = message_chat_id + if updated_at is not UNSET: + field_dict["updated_at"] = updated_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_id = d.pop("message_id", UNSET) + + message_chat_id = d.pop("message_chat_id", UNSET) + + _updated_at = d.pop("updated_at", UNSET) + updated_at: Union[Unset, datetime.datetime] + if isinstance(_updated_at, Unset): + updated_at = UNSET + else: + updated_at = isoparse(_updated_at) + + create_thread_response_200_data = cls( + id=id, + chat_id=chat_id, + message_id=message_id, + message_chat_id=message_chat_id, + updated_at=updated_at, + ) + + create_thread_response_200_data.additional_properties = d + return create_thread_response_200_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py new file mode 100644 index 0000000..100dc9c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400") + + +@_attrs_define +class DeleteMessageReactionsResponse400: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item import ( + DeleteMessageReactionsResponse400ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_400 = cls( + errors=errors, + ) + + delete_message_reactions_response_400.additional_properties = d + return delete_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py new file mode 100644 index 0000000..4a61277 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse400ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_400_errors_item.additional_properties = d + return delete_message_reactions_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py new file mode 100644 index 0000000..d3d26c9 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_400_errors_item_payload = cls() + + delete_message_reactions_response_400_errors_item_payload.additional_properties = d + return delete_message_reactions_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py new file mode 100644 index 0000000..9f918a0 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404") + + +@_attrs_define +class DeleteMessageReactionsResponse404: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item import ( + DeleteMessageReactionsResponse404ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_404 = cls( + errors=errors, + ) + + delete_message_reactions_response_404.additional_properties = d + return delete_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py new file mode 100644 index 0000000..849db9d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse404ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_404_errors_item.additional_properties = d + return delete_message_reactions_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py new file mode 100644 index 0000000..f2fa5b5 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_404_errors_item_payload = cls() + + delete_message_reactions_response_404_errors_item_payload.additional_properties = d + return delete_message_reactions_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/direct_response.py b/pachca_api/pachca_api_open_api_3_0_client/models/direct_response.py new file mode 100644 index 0000000..aef4bc1 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/direct_response.py @@ -0,0 +1,195 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DirectResponse") + + +@_attrs_define +class DirectResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + file (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + file: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + file = self.file + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + def to_multipart(self) -> dict[str, Any]: + content_disposition = ( + self.content_disposition + if isinstance(self.content_disposition, Unset) + else (None, str(self.content_disposition).encode(), "text/plain") + ) + + acl = self.acl if isinstance(self.acl, Unset) else (None, str(self.acl).encode(), "text/plain") + + policy = self.policy if isinstance(self.policy, Unset) else (None, str(self.policy).encode(), "text/plain") + + x_amz_credential = ( + self.x_amz_credential + if isinstance(self.x_amz_credential, Unset) + else (None, str(self.x_amz_credential).encode(), "text/plain") + ) + + x_amz_algorithm = ( + self.x_amz_algorithm + if isinstance(self.x_amz_algorithm, Unset) + else (None, str(self.x_amz_algorithm).encode(), "text/plain") + ) + + x_amz_date = ( + self.x_amz_date + if isinstance(self.x_amz_date, Unset) + else (None, str(self.x_amz_date).encode(), "text/plain") + ) + + x_amz_signature = ( + self.x_amz_signature + if isinstance(self.x_amz_signature, Unset) + else (None, str(self.x_amz_signature).encode(), "text/plain") + ) + + key = self.key if isinstance(self.key, Unset) else (None, str(self.key).encode(), "text/plain") + + file = self.file if isinstance(self.file, Unset) else (None, str(self.file).encode(), "text/plain") + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = (None, str(prop).encode(), "text/plain") + + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + file = d.pop("file", UNSET) + + direct_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + file=file, + ) + + direct_response.additional_properties = d + return direct_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages.py b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages.py new file mode 100644 index 0000000..8e6439d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages.py @@ -0,0 +1,113 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + +T = TypeVar("T", bound="EditMessages") + + +@_attrs_define +class EditMessages: + """Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Attributes: + content (Union[Unset, str]): Текст сообщения Default: 'Текст сообщения'. + files (Union[Unset, EditMessagesFiles]): + buttons (Union[Unset, list[list['EditMessagesButtonsItemItem']]]): Массив строк, каждая из которых представлена + массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в + статье. Для удаления кнопок у сообщения пришлите пустой массив. + """ + + content: Union[Unset, str] = "Текст сообщения" + files: Union[Unset, "EditMessagesFiles"] = UNSET + buttons: Union[Unset, list[list["EditMessagesButtonsItemItem"]]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content = self.content + + files: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.files, Unset): + files = self.files.to_dict() + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for buttons_item_data in self.buttons: + buttons_item = [] + for buttons_item_item_data in buttons_item_data: + buttons_item_item = buttons_item_item_data.to_dict() + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content is not UNSET: + field_dict["content"] = content + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + d = src_dict.copy() + content = d.pop("content", UNSET) + + _files = d.pop("files", UNSET) + files: Union[Unset, EditMessagesFiles] + if isinstance(_files, Unset): + files = UNSET + else: + files = EditMessagesFiles.from_dict(_files) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for buttons_item_data in _buttons or []: + buttons_item = [] + _buttons_item = buttons_item_data + for buttons_item_item_data in _buttons_item: + buttons_item_item = EditMessagesButtonsItemItem.from_dict(buttons_item_item_data) + + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + edit_messages = cls( + content=content, + files=files, + buttons=buttons, + ) + + edit_messages.additional_properties = d + return edit_messages + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py new file mode 100644 index 0000000..22494f8 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py @@ -0,0 +1,76 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesButtonsItemItem") + + +@_attrs_define +class EditMessagesButtonsItemItem: + """ + Attributes: + text (Union[Unset, str]): Текст, отображаемый на кнопке пользователю + url (Union[Unset, str]): Ссылка, которая будет открыта по нажатию кнопки + data (Union[Unset, str]): Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + """ + + text: Union[Unset, str] = UNSET + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if text is not UNSET: + field_dict["text"] = text + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text", UNSET) + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + edit_messages_buttons_item_item = cls( + text=text, + url=url, + data=data, + ) + + edit_messages_buttons_item_item.additional_properties = d + return edit_messages_buttons_item_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files.py b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files.py new file mode 100644 index 0000000..f42b7bb --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files.py @@ -0,0 +1,95 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.edit_messages_files_file_type import EditMessagesFilesFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesFiles") + + +@_attrs_define +class EditMessagesFiles: + """ + Attributes: + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, EditMessagesFilesFileType]): + size (Union[Unset, int]): Размер файла в байтах, отображаемый пользователю Default: 1234. + """ + + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, EditMessagesFilesFileType] = UNSET + size: Union[Unset, int] = 1234 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if size is not UNSET: + field_dict["size"] = size + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, EditMessagesFilesFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = EditMessagesFilesFileType(_file_type) + + size = d.pop("size", UNSET) + + edit_messages_files = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + edit_messages_files.additional_properties = d + return edit_messages_files + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py new file mode 100644 index 0000000..a78a223 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class EditMessagesFilesFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/employee.py b/pachca_api/pachca_api_open_api_3_0_client/models/employee.py new file mode 100644 index 0000000..9011165 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/employee.py @@ -0,0 +1,275 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="Employee") + + +@_attrs_define +class Employee: + """ + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + user_status (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + title (Union[Unset, str]): Должность + created_at (Union[Unset, datetime.datetime]): Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone (Union[Unset, str]): Часовой пояс пользователя + image_url (Union[None, Unset, str]): Ссылка на скачивание аватарки + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + user_status: Union["StatusType0", None, Unset] = UNSET + title: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + time_zone: Union[Unset, str] = UNSET + image_url: Union[None, Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + user_status: Union[None, Unset, dict[str, Any]] + if isinstance(self.user_status, Unset): + user_status = UNSET + elif isinstance(self.user_status, StatusType0): + user_status = self.user_status.to_dict() + else: + user_status = self.user_status + + title = self.title + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + time_zone = self.time_zone + + image_url: Union[None, Unset, str] + if isinstance(self.image_url, Unset): + image_url = UNSET + else: + image_url = self.image_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + if user_status is not UNSET: + field_dict["user_status"] = user_status + if title is not UNSET: + field_dict["title"] = title + if created_at is not UNSET: + field_dict["created_at"] = created_at + if time_zone is not UNSET: + field_dict["time_zone"] = time_zone + if image_url is not UNSET: + field_dict["image_url"] = image_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + def _parse_user_status(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + user_status = _parse_user_status(d.pop("user_status", UNSET)) + + title = d.pop("title", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + time_zone = d.pop("time_zone", UNSET) + + def _parse_image_url(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + image_url = _parse_image_url(d.pop("image_url", UNSET)) + + employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + user_status=user_status, + title=title, + created_at=created_at, + time_zone=time_zone, + image_url=image_url, + ) + + employee.additional_properties = d + return employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/error.py b/pachca_api/pachca_api_open_api_3_0_client/models/error.py new file mode 100644 index 0000000..e9e73d2 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/error.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error_payload import ErrorPayload + + +T = TypeVar("T", bound="Error") + + +@_attrs_define +class Error: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error_payload import ErrorPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorPayload.from_dict(_payload) + + error = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + error.additional_properties = d + return error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/error_payload.py b/pachca_api/pachca_api_open_api_3_0_client/models/error_payload.py new file mode 100644 index 0000000..9133249 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/error_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorPayload") + + +@_attrs_define +class ErrorPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error_payload = cls() + + error_payload.additional_properties = d + return error_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/errors_code.py b/pachca_api/pachca_api_open_api_3_0_client/models/errors_code.py new file mode 100644 index 0000000..52b0dee --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/errors_code.py @@ -0,0 +1,108 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code_payload import ErrorsCodePayload + + +T = TypeVar("T", bound="ErrorsCode") + + +@_attrs_define +class ErrorsCode: + """Bad Request + + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorsCodePayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorsCodePayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code_payload import ErrorsCodePayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorsCodePayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorsCodePayload.from_dict(_payload) + + errors_code = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + errors_code.additional_properties = d + return errors_code + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/errors_code_payload.py b/pachca_api/pachca_api_open_api_3_0_client/models/errors_code_payload.py new file mode 100644 index 0000000..8128de2 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/errors_code_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorsCodePayload") + + +@_attrs_define +class ErrorsCodePayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + errors_code_payload = cls() + + errors_code_payload.additional_properties = d + return errors_code_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/file_response.py b/pachca_api/pachca_api_open_api_3_0_client/models/file_response.py new file mode 100644 index 0000000..5bb1dc4 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/file_response.py @@ -0,0 +1,130 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FileResponse") + + +@_attrs_define +class FileResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + direct_url (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + direct_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + direct_url = self.direct_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if direct_url is not UNSET: + field_dict["direct_url"] = direct_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + direct_url = d.pop("direct_url", UNSET) + + file_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + direct_url=direct_url, + ) + + file_response.additional_properties = d + return file_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_200.py new file mode 100644 index 0000000..274ed8c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatResponse200") + + +@_attrs_define +class GetChatResponse200: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + get_chat_response_200 = cls( + data=data, + ) + + get_chat_response_200.additional_properties = d + return get_chat_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_404.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_404.py new file mode 100644 index 0000000..6aaf8b1 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatResponse404") + + +@_attrs_define +class GetChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chat_response_404 = cls( + errors=errors, + ) + + get_chat_response_404.additional_properties = d + return get_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_availability.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_availability.py new file mode 100644 index 0000000..b76cb4d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_availability.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsAvailability(str, Enum): + IS_MEMBER = "is_member" + PUBLIC = "public" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_200.py new file mode 100644 index 0000000..3917a9f --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatsResponse200") + + +@_attrs_define +class GetChatsResponse200: + """ + Attributes: + data (Union[Unset, list['Chat']]): + """ + + data: Union[Unset, list["Chat"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Chat.from_dict(data_item_data) + + data.append(data_item) + + get_chats_response_200 = cls( + data=data, + ) + + get_chats_response_200.additional_properties = d + return get_chats_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_400.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_400.py new file mode 100644 index 0000000..005a6a3 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_400.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code import ErrorsCode + + +T = TypeVar("T", bound="GetChatsResponse400") + + +@_attrs_define +class GetChatsResponse400: + """ + Attributes: + errors (Union[Unset, ErrorsCode]): Bad Request + """ + + errors: Union[Unset, "ErrorsCode"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.errors, Unset): + errors = self.errors.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code import ErrorsCode + + d = src_dict.copy() + _errors = d.pop("errors", UNSET) + errors: Union[Unset, ErrorsCode] + if isinstance(_errors, Unset): + errors = UNSET + else: + errors = ErrorsCode.from_dict(_errors) + + get_chats_response_400 = cls( + errors=errors, + ) + + get_chats_response_400.additional_properties = d + return get_chats_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_404.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_404.py new file mode 100644 index 0000000..1553a65 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse404") + + +@_attrs_define +class GetChatsResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_404 = cls( + errors=errors, + ) + + get_chats_response_404.additional_properties = d + return get_chats_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_422.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_422.py new file mode 100644 index 0000000..5248609 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse422") + + +@_attrs_define +class GetChatsResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_422 = cls( + errors=errors, + ) + + get_chats_response_422.additional_properties = d + return get_chats_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_sortid.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_sortid.py new file mode 100644 index 0000000..0de410c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_chats_sortid.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsSortid(str, Enum): + ASC = "asc" + DESC = "desc" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py new file mode 100644 index 0000000..93ea91d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_common_methods import QueryCommonMethods + + +T = TypeVar("T", bound="GetCommonMethodsResponse200") + + +@_attrs_define +class GetCommonMethodsResponse200: + """ + Attributes: + data (Union[Unset, list['QueryCommonMethods']]): + """ + + data: Union[Unset, list["QueryCommonMethods"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_common_methods import QueryCommonMethods + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = QueryCommonMethods.from_dict(data_item_data) + + data.append(data_item) + + get_common_methods_response_200 = cls( + data=data, + ) + + get_common_methods_response_200.additional_properties = d + return get_common_methods_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_employee_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_employee_response_200.py new file mode 100644 index 0000000..b970ea8 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_employee_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeeResponse200") + + +@_attrs_define +class GetEmployeeResponse200: + """ + Attributes: + data (Union[Unset, Employee]): + """ + + data: Union[Unset, "Employee"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Employee] + if isinstance(_data, Unset): + data = UNSET + else: + data = Employee.from_dict(_data) + + get_employee_response_200 = cls( + data=data, + ) + + get_employee_response_200.additional_properties = d + return get_employee_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_employees_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_employees_response_200.py new file mode 100644 index 0000000..978802c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeesResponse200") + + +@_attrs_define +class GetEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['Employee']]): + """ + + data: Union[Unset, list["Employee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Employee.from_dict(data_item_data) + + data.append(data_item) + + get_employees_response_200 = cls( + data=data, + ) + + get_employees_response_200.additional_properties = d + return get_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py new file mode 100644 index 0000000..52837e1 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetListMessageResponse200") + + +@_attrs_define +class GetListMessageResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + get_list_message_response_200 = cls( + data=data, + ) + + get_list_message_response_200.additional_properties = d + return get_list_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py new file mode 100644 index 0000000..eaa7bb5 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py @@ -0,0 +1,68 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="GetMessageReactionsBody") + + +@_attrs_define +class GetMessageReactionsBody: + """ + Attributes: + per (Union[Unset, int]): Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). + Default: 50. + page (Union[Unset, int]): Номер страницы выборки (по умолчанию 1). Default: 1. + """ + + per: Union[Unset, int] = 50 + page: Union[Unset, int] = 1 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + per = self.per + + page = self.page + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if per is not UNSET: + field_dict["per"] = per + if page is not UNSET: + field_dict["page"] = page + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + per = d.pop("per", UNSET) + + page = d.pop("page", UNSET) + + get_message_reactions_body = cls( + per=per, + page=page, + ) + + get_message_reactions_body.additional_properties = d + return get_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py new file mode 100644 index 0000000..3c50c79 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.reaction import Reaction + + +T = TypeVar("T", bound="GetMessageReactionsResponse200") + + +@_attrs_define +class GetMessageReactionsResponse200: + """ + Attributes: + data (Union[Unset, list['Reaction']]): + """ + + data: Union[Unset, list["Reaction"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.reaction import Reaction + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Reaction.from_dict(data_item_data) + + data.append(data_item) + + get_message_reactions_response_200 = cls( + data=data, + ) + + get_message_reactions_response_200.additional_properties = d + return get_message_reactions_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_message_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_message_response_200.py new file mode 100644 index 0000000..677295d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_message_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetMessageResponse200") + + +@_attrs_define +class GetMessageResponse200: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + get_message_response_200 = cls( + data=data, + ) + + get_message_response_200.additional_properties = d + return get_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_status_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_status_response_200.py new file mode 100644 index 0000000..7e93886 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_status_response_200.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="GetStatusResponse200") + + +@_attrs_define +class GetStatusResponse200: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + get_status_response_200 = cls( + data=data, + ) + + get_status_response_200.additional_properties = d + return get_status_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_200.py new file mode 100644 index 0000000..188f734 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagResponse200") + + +@_attrs_define +class GetTagResponse200: + """ + Attributes: + data (Union[Unset, Tag]): Для получения тега вам необходимо знать его id и указать его в URL запроса. + """ + + data: Union[Unset, "Tag"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Tag] + if isinstance(_data, Unset): + data = UNSET + else: + data = Tag.from_dict(_data) + + get_tag_response_200 = cls( + data=data, + ) + + get_tag_response_200.additional_properties = d + return get_tag_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404.py new file mode 100644 index 0000000..c3c8ead --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + +T = TypeVar("T", bound="GetTagResponse404") + + +@_attrs_define +class GetTagResponse404: + """ + Attributes: + errors (Union[Unset, list['GetTagResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["GetTagResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tag_response_404 = cls( + errors=errors, + ) + + get_tag_response_404.additional_properties = d + return get_tag_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py new file mode 100644 index 0000000..18649e6 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagResponse404ErrorsItem") + + +@_attrs_define +class GetTagResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, GetTagResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagResponse404ErrorsItemPayload.from_dict(_payload) + + get_tag_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tag_response_404_errors_item.additional_properties = d + return get_tag_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py new file mode 100644 index 0000000..b6d7c6c --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagResponse404ErrorsItemPayload") + + +@_attrs_define +class GetTagResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tag_response_404_errors_item_payload = cls() + + get_tag_response_404_errors_item_payload.additional_properties = d + return get_tag_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py new file mode 100644 index 0000000..682b3fa --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee import BaseEmployee + + +T = TypeVar("T", bound="GetTagsEmployeesResponse200") + + +@_attrs_define +class GetTagsEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['BaseEmployee']]): + """ + + data: Union[Unset, list["BaseEmployee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee import BaseEmployee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = BaseEmployee.from_dict(data_item_data) + + data.append(data_item) + + get_tags_employees_response_200 = cls( + data=data, + ) + + get_tags_employees_response_200.additional_properties = d + return get_tags_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_200.py new file mode 100644 index 0000000..1ae18d4 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagsResponse200") + + +@_attrs_define +class GetTagsResponse200: + """ + Attributes: + data (Union[Unset, list['Tag']]): + """ + + data: Union[Unset, list["Tag"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Tag.from_dict(data_item_data) + + data.append(data_item) + + get_tags_response_200 = cls( + data=data, + ) + + get_tags_response_200.additional_properties = d + return get_tags_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400.py new file mode 100644 index 0000000..1865c60 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + +T = TypeVar("T", bound="GetTagsResponse400") + + +@_attrs_define +class GetTagsResponse400: + """ + Attributes: + errors (Union[Unset, list['GetTagsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["GetTagsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tags_response_400 = cls( + errors=errors, + ) + + get_tags_response_400.additional_properties = d + return get_tags_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py new file mode 100644 index 0000000..bd7859d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItem") + + +@_attrs_define +class GetTagsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, GetTagsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagsResponse400ErrorsItemPayload.from_dict(_payload) + + get_tags_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tags_response_400_errors_item.additional_properties = d + return get_tags_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py new file mode 100644 index 0000000..2e1d941 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItemPayload") + + +@_attrs_define +class GetTagsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tags_response_400_errors_item_payload = cls() + + get_tags_response_400_errors_item_payload.additional_properties = d + return get_tags_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/message.py b/pachca_api/pachca_api_open_api_3_0_client/models/message.py new file mode 100644 index 0000000..bb01030 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/message.py @@ -0,0 +1,272 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..models.message_entity_type import MessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + +T = TypeVar("T", bound="Message") + + +@_attrs_define +class Message: + """ + Attributes: + entity_type (Union[Unset, MessageEntityType]): Default: MessageEntityType.DISCUSSION. + entity_id (Union[Unset, int]): + content (Union[Unset, str]): + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + user_id (Union[Unset, int]): + created_at (Union[Unset, datetime.datetime]): + files (Union[Unset, list['MessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + thread (Union['MessageThread', None, Unset]): + forwarding (Union['MessageForwarding', None, Unset]): + parent_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому написан ответ. Возвращается как + null, если сообщение не является ответом. + """ + + entity_type: Union[Unset, MessageEntityType] = MessageEntityType.DISCUSSION + entity_id: Union[Unset, int] = UNSET + content: Union[Unset, str] = UNSET + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + files: Union[Unset, list["MessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + thread: Union["MessageThread", None, Unset] = UNSET + forwarding: Union["MessageForwarding", None, Unset] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + entity_id = self.entity_id + + content = self.content + + id = self.id + + chat_id = self.chat_id + + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + thread: Union[None, Unset, dict[str, Any]] + if isinstance(self.thread, Unset): + thread = UNSET + elif isinstance(self.thread, MessageThread): + thread = self.thread.to_dict() + else: + thread = self.thread + + forwarding: Union[None, Unset, dict[str, Any]] + if isinstance(self.forwarding, Unset): + forwarding = UNSET + elif isinstance(self.forwarding, MessageForwarding): + forwarding = self.forwarding.to_dict() + else: + forwarding = self.forwarding + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if entity_id is not UNSET: + field_dict["entity_id"] = entity_id + if content is not UNSET: + field_dict["content"] = content + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if thread is not UNSET: + field_dict["thread"] = thread + if forwarding is not UNSET: + field_dict["forwarding"] = forwarding + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + d = src_dict.copy() + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, MessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = MessageEntityType(_entity_type) + + entity_id = d.pop("entity_id", UNSET) + + content = d.pop("content", UNSET) + + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = MessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_thread(data: object) -> Union["MessageThread", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + thread_type_0 = MessageThread.from_dict(data) + + return thread_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageThread", None, Unset], data) + + thread = _parse_thread(d.pop("thread", UNSET)) + + def _parse_forwarding(data: object) -> Union["MessageForwarding", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + forwarding_type_0 = MessageForwarding.from_dict(data) + + return forwarding_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageForwarding", None, Unset], data) + + forwarding = _parse_forwarding(d.pop("forwarding", UNSET)) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + message = cls( + entity_type=entity_type, + entity_id=entity_id, + content=content, + id=id, + chat_id=chat_id, + user_id=user_id, + created_at=created_at, + files=files, + buttons=buttons, + thread=thread, + forwarding=forwarding, + parent_message_id=parent_message_id, + ) + + message.additional_properties = d + return message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/message_entity_type.py b/pachca_api/pachca_api_open_api_3_0_client/models/message_entity_type.py new file mode 100644 index 0000000..e8a126a --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class MessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/message_files_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/message_files_item.py new file mode 100644 index 0000000..21509d2 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/message_files_item.py @@ -0,0 +1,104 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.message_files_item_file_type import MessageFilesItemFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageFilesItem") + + +@_attrs_define +class MessageFilesItem: + """ + Attributes: + id (Union[Unset, int]): + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, MessageFilesItemFileType]): + url (Union[Unset, str]): Размер файла в байтах, отображаемый пользователю + """ + + id: Union[Unset, int] = UNSET + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, MessageFilesItemFileType] = UNSET + url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if url is not UNSET: + field_dict["url"] = url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, MessageFilesItemFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = MessageFilesItemFileType(_file_type) + + url = d.pop("url", UNSET) + + message_files_item = cls( + id=id, + key=key, + name=name, + file_type=file_type, + url=url, + ) + + message_files_item.additional_properties = d + return message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py b/pachca_api/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py new file mode 100644 index 0000000..1e00e5b --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class MessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/message_forwarding.py b/pachca_api/pachca_api_open_api_3_0_client/models/message_forwarding.py new file mode 100644 index 0000000..6ce981d --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/message_forwarding.py @@ -0,0 +1,153 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageForwarding") + + +@_attrs_define +class MessageForwarding: + """ + Attributes: + original_message_id (Union[Unset, int]): Идентификатор оригинального сообщения + original_chat_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + author_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + original_created_at (Union[Unset, int]): Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id (Union[None, Unset, int]): Идентификатор треда, в котором находится оригинальное сообщение. + Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому был создан тред, в + котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + original_thread_parent_chat_id (Union[None, Unset, int]): Идентификатор чата сообщения, к которому был создан + тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + """ + + original_message_id: Union[Unset, int] = UNSET + original_chat_id: Union[Unset, int] = UNSET + author_id: Union[Unset, int] = UNSET + original_created_at: Union[Unset, int] = UNSET + original_thread_id: Union[None, Unset, int] = UNSET + original_thread_message_id: Union[None, Unset, int] = UNSET + original_thread_parent_chat_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + original_message_id = self.original_message_id + + original_chat_id = self.original_chat_id + + author_id = self.author_id + + original_created_at = self.original_created_at + + original_thread_id: Union[None, Unset, int] + if isinstance(self.original_thread_id, Unset): + original_thread_id = UNSET + else: + original_thread_id = self.original_thread_id + + original_thread_message_id: Union[None, Unset, int] + if isinstance(self.original_thread_message_id, Unset): + original_thread_message_id = UNSET + else: + original_thread_message_id = self.original_thread_message_id + + original_thread_parent_chat_id: Union[None, Unset, int] + if isinstance(self.original_thread_parent_chat_id, Unset): + original_thread_parent_chat_id = UNSET + else: + original_thread_parent_chat_id = self.original_thread_parent_chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if original_message_id is not UNSET: + field_dict["original_message_id"] = original_message_id + if original_chat_id is not UNSET: + field_dict["original_chat_id"] = original_chat_id + if author_id is not UNSET: + field_dict["author_id"] = author_id + if original_created_at is not UNSET: + field_dict["original_created_at"] = original_created_at + if original_thread_id is not UNSET: + field_dict["original_thread_id"] = original_thread_id + if original_thread_message_id is not UNSET: + field_dict["original_thread_message_id"] = original_thread_message_id + if original_thread_parent_chat_id is not UNSET: + field_dict["original_thread_parent_chat_id"] = original_thread_parent_chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + original_message_id = d.pop("original_message_id", UNSET) + + original_chat_id = d.pop("original_chat_id", UNSET) + + author_id = d.pop("author_id", UNSET) + + original_created_at = d.pop("original_created_at", UNSET) + + def _parse_original_thread_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_id = _parse_original_thread_id(d.pop("original_thread_id", UNSET)) + + def _parse_original_thread_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_message_id = _parse_original_thread_message_id(d.pop("original_thread_message_id", UNSET)) + + def _parse_original_thread_parent_chat_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_parent_chat_id = _parse_original_thread_parent_chat_id( + d.pop("original_thread_parent_chat_id", UNSET) + ) + + message_forwarding = cls( + original_message_id=original_message_id, + original_chat_id=original_chat_id, + author_id=author_id, + original_created_at=original_created_at, + original_thread_id=original_thread_id, + original_thread_message_id=original_thread_message_id, + original_thread_parent_chat_id=original_thread_parent_chat_id, + ) + + message_forwarding.additional_properties = d + return message_forwarding + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/message_thread.py b/pachca_api/pachca_api_open_api_3_0_client/models/message_thread.py new file mode 100644 index 0000000..ddd18f0 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/message_thread.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageThread") + + +@_attrs_define +class MessageThread: + """ + Attributes: + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_thread = cls( + id=id, + chat_id=chat_id, + ) + + message_thread.additional_properties = d + return message_thread + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/not_found.py b/pachca_api/pachca_api_open_api_3_0_client/models/not_found.py new file mode 100644 index 0000000..c24e928 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/not_found.py @@ -0,0 +1,59 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="NotFound") + + +@_attrs_define +class NotFound: + """Объект не найден + + Attributes: + detail (Union[Unset, str]): Описание ошибки Example: Страница не найдена.. + """ + + detail: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if detail is not UNSET: + field_dict["detail"] = detail + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + detail = d.pop("detail", UNSET) + + not_found = cls( + detail=detail, + ) + + not_found.additional_properties = d + return not_found + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py new file mode 100644 index 0000000..620f8dc --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py @@ -0,0 +1,69 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMembersToChatsBody") + + +@_attrs_define +class PostMembersToChatsBody: + """ + Attributes: + member_ids (list[int]): Example: [186, 187]. + silent (Union[Unset, bool]): + """ + + member_ids: list[int] + silent: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + member_ids = self.member_ids + + silent = self.silent + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "member_ids": member_ids, + } + ) + if silent is not UNSET: + field_dict["silent"] = silent + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + member_ids = cast(list[int], d.pop("member_ids")) + + silent = d.pop("silent", UNSET) + + post_members_to_chats_body = cls( + member_ids=member_ids, + silent=silent, + ) + + post_members_to_chats_body.additional_properties = d + return post_members_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py new file mode 100644 index 0000000..fffa22a --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostMessageReactionsBody") + + +@_attrs_define +class PostMessageReactionsBody: + """ + Attributes: + code (str): Emoji в строковом формате для добавления реакции. + """ + + code: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "code": code, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + code = d.pop("code") + + post_message_reactions_body = cls( + code=code, + ) + + post_message_reactions_body.additional_properties = d + return post_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py new file mode 100644 index 0000000..50b0078 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse400") + + +@_attrs_define +class PostMessageReactionsResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_400 = cls( + error=error, + ) + + post_message_reactions_response_400.additional_properties = d + return post_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py new file mode 100644 index 0000000..cd52780 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse403") + + +@_attrs_define +class PostMessageReactionsResponse403: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_403 = cls( + error=error, + ) + + post_message_reactions_response_403.additional_properties = d + return post_message_reactions_response_403 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py new file mode 100644 index 0000000..1a26c89 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse404") + + +@_attrs_define +class PostMessageReactionsResponse404: + """ + Attributes: + error (Union[Unset, str]): Сообщение не найдено. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_404 = cls( + error=error, + ) + + post_message_reactions_response_404.additional_properties = d + return post_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py new file mode 100644 index 0000000..23040f4 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostTagsToChatsBody") + + +@_attrs_define +class PostTagsToChatsBody: + """ + Attributes: + group_tag_ids (list[int]): Example: [86, 18]. + """ + + group_tag_ids: list[int] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + group_tag_ids = self.group_tag_ids + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "group_tag_ids": group_tag_ids, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + group_tag_ids = cast(list[int], d.pop("group_tag_ids")) + + post_tags_to_chats_body = cls( + group_tag_ids=group_tag_ids, + ) + + post_tags_to_chats_body.additional_properties = d + return post_tags_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body.py new file mode 100644 index 0000000..1abee57 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_body_task import PostTasksBodyTask + + +T = TypeVar("T", bound="PostTasksBody") + + +@_attrs_define +class PostTasksBody: + """ + Attributes: + task (Union[Unset, PostTasksBodyTask]): + """ + + task: Union[Unset, "PostTasksBodyTask"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + task: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.task, Unset): + task = self.task.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if task is not UNSET: + field_dict["task"] = task + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_body_task import PostTasksBodyTask + + d = src_dict.copy() + _task = d.pop("task", UNSET) + task: Union[Unset, PostTasksBodyTask] + if isinstance(_task, Unset): + task = UNSET + else: + task = PostTasksBodyTask.from_dict(_task) + + post_tasks_body = cls( + task=task, + ) + + post_tasks_body.additional_properties = d + return post_tasks_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py new file mode 100644 index 0000000..f85bf85 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py @@ -0,0 +1,123 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem + + +T = TypeVar("T", bound="PostTasksBodyTask") + + +@_attrs_define +class PostTasksBodyTask: + """ + Attributes: + kind (str): Тип напоминания (call, meeting, reminder, event, email) + content (str): Описание напоминания + due_at (datetime.datetime): Срок выполнения напоминания (ISO-8601) + priority (Union[Unset, int]): Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей + custom_properties (Union[Unset, list['PostTasksBodyTaskCustomPropertiesItem']]): + """ + + kind: str + content: str + due_at: datetime.datetime + priority: Union[Unset, int] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["PostTasksBodyTaskCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind = self.kind + + content = self.content + + due_at = self.due_at.isoformat() + + priority = self.priority + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "content": content, + "due_at": due_at, + } + ) + if priority is not UNSET: + field_dict["priority"] = priority + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem + + d = src_dict.copy() + kind = d.pop("kind") + + content = d.pop("content") + + due_at = isoparse(d.pop("due_at")) + + priority = d.pop("priority", UNSET) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = PostTasksBodyTaskCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + post_tasks_body_task = cls( + kind=kind, + content=content, + due_at=due_at, + priority=priority, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + post_tasks_body_task.additional_properties = d + return post_tasks_body_task + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py new file mode 100644 index 0000000..279e511 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksBodyTaskCustomPropertiesItem") + + +@_attrs_define +class PostTasksBodyTaskCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + value (Union[Unset, str]): Значение поля + """ + + id: Union[Unset, int] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + value = d.pop("value", UNSET) + + post_tasks_body_task_custom_properties_item = cls( + id=id, + value=value, + ) + + post_tasks_body_task_custom_properties_item.additional_properties = d + return post_tasks_body_task_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py new file mode 100644 index 0000000..5dcd6b7 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_response_201_data import PostTasksResponse201Data + + +T = TypeVar("T", bound="PostTasksResponse201") + + +@_attrs_define +class PostTasksResponse201: + """ + Attributes: + data (Union[Unset, PostTasksResponse201Data]): + """ + + data: Union[Unset, "PostTasksResponse201Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_response_201_data import PostTasksResponse201Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, PostTasksResponse201Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = PostTasksResponse201Data.from_dict(_data) + + post_tasks_response_201 = cls( + data=data, + ) + + post_tasks_response_201.additional_properties = d + return post_tasks_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py new file mode 100644 index 0000000..b714c69 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py @@ -0,0 +1,177 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.post_tasks_response_201_data_custom_properties_item import ( + PostTasksResponse201DataCustomPropertiesItem, + ) + + +T = TypeVar("T", bound="PostTasksResponse201Data") + + +@_attrs_define +class PostTasksResponse201Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного напоминания + kind (Union[Unset, str]): Тип + content (Union[Unset, str]): Описание + due_at (Union[Unset, datetime.datetime]): Срок выполнения (ISO-8601) + priority (Union[Unset, int]): Приоритет + user_id (Union[Unset, int]): Идентификатор пользователя-создателя + status (Union[Unset, str]): Статус напоминания + created_at (Union[Unset, datetime.datetime]): Дата и время создания + performer_ids (Union[Unset, list[int]]): + custom_properties (Union[Unset, list['PostTasksResponse201DataCustomPropertiesItem']]): + """ + + id: Union[Unset, int] = UNSET + kind: Union[Unset, str] = UNSET + content: Union[Unset, str] = UNSET + due_at: Union[Unset, datetime.datetime] = UNSET + priority: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + status: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["PostTasksResponse201DataCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + kind = self.kind + + content = self.content + + due_at: Union[Unset, str] = UNSET + if not isinstance(self.due_at, Unset): + due_at = self.due_at.isoformat() + + priority = self.priority + + user_id = self.user_id + + status = self.status + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if kind is not UNSET: + field_dict["kind"] = kind + if content is not UNSET: + field_dict["content"] = content + if due_at is not UNSET: + field_dict["due_at"] = due_at + if priority is not UNSET: + field_dict["priority"] = priority + if user_id is not UNSET: + field_dict["user_id"] = user_id + if status is not UNSET: + field_dict["status"] = status + if created_at is not UNSET: + field_dict["created_at"] = created_at + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.post_tasks_response_201_data_custom_properties_item import ( + PostTasksResponse201DataCustomPropertiesItem, + ) + + d = src_dict.copy() + id = d.pop("id", UNSET) + + kind = d.pop("kind", UNSET) + + content = d.pop("content", UNSET) + + _due_at = d.pop("due_at", UNSET) + due_at: Union[Unset, datetime.datetime] + if isinstance(_due_at, Unset): + due_at = UNSET + else: + due_at = isoparse(_due_at) + + priority = d.pop("priority", UNSET) + + user_id = d.pop("user_id", UNSET) + + status = d.pop("status", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = PostTasksResponse201DataCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + post_tasks_response_201_data = cls( + id=id, + kind=kind, + content=content, + due_at=due_at, + priority=priority, + user_id=user_id, + status=status, + created_at=created_at, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + post_tasks_response_201_data.additional_properties = d + return post_tasks_response_201_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py new file mode 100644 index 0000000..1dc217e --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksResponse201DataCustomPropertiesItem") + + +@_attrs_define +class PostTasksResponse201DataCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + post_tasks_response_201_data_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + post_tasks_response_201_data_custom_properties_item.additional_properties = d + return post_tasks_response_201_data_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py new file mode 100644 index 0000000..e5ca651 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostTasksResponse400") + + +@_attrs_define +class PostTasksResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_tasks_response_400 = cls( + error=error, + ) + + post_tasks_response_400.additional_properties = d + return post_tasks_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_body.py b/pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_body.py new file mode 100644 index 0000000..24a5140 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_body.py @@ -0,0 +1,72 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages import EditMessages + + +T = TypeVar("T", bound="PutMessagesIdBody") + + +@_attrs_define +class PutMessagesIdBody: + """ + Attributes: + message (Union[Unset, EditMessages]): Для получения сообщения вам необходимо знать его id и указать его в URL + запроса. + """ + + message: Union[Unset, "EditMessages"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages import EditMessages + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, EditMessages] + if isinstance(_message, Unset): + message = UNSET + else: + message = EditMessages.from_dict(_message) + + put_messages_id_body = cls( + message=message, + ) + + put_messages_id_body.additional_properties = d + return put_messages_id_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py b/pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py new file mode 100644 index 0000000..5cb478f --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="PutMessagesIdResponse200") + + +@_attrs_define +class PutMessagesIdResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): Созданное сообщение + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + put_messages_id_response_200 = cls( + data=data, + ) + + put_messages_id_response_200.additional_properties = d + return put_messages_id_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/put_status_response_201.py b/pachca_api/pachca_api_open_api_3_0_client/models/put_status_response_201.py new file mode 100644 index 0000000..a34d4e0 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/put_status_response_201.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="PutStatusResponse201") + + +@_attrs_define +class PutStatusResponse201: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + put_status_response_201 = cls( + data=data, + ) + + put_status_response_201.additional_properties = d + return put_status_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/query_chat.py b/pachca_api/pachca_api_open_api_3_0_client/models/query_chat.py new file mode 100644 index 0000000..f3e1788 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/query_chat.py @@ -0,0 +1,91 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryChat") + + +@_attrs_define +class QueryChat: + """Собранный объект параметров создаваемой беседы или канала + + Attributes: + name (str): Название Example: 🤿 aqua. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, которые станут участниками Example: + [186, 187]. + channel (Union[Unset, bool]): Тип: беседа (по умолчанию, false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (по умолчанию, false) или открытый (true) + """ + + name: str + member_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + channel = self.channel + + public = self.public + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + query_chat = cls( + name=name, + member_ids=member_ids, + channel=channel, + public=public, + ) + + query_chat.additional_properties = d + return query_chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/query_common_methods.py b/pachca_api/pachca_api_open_api_3_0_client/models/query_common_methods.py new file mode 100644 index 0000000..f575b43 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/query_common_methods.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryCommonMethods") + + +@_attrs_define +class QueryCommonMethods: + """получение списка актульных полей сущности. + + Attributes: + id (Union[Unset, int]): Название поля Example: 1. + name (Union[Unset, str]): Идентификатор поля Example: Дата рождения. + data_type (Union[Unset, str]): тип поля (string, number, date или link) Example: number. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + query_common_methods = cls( + id=id, + name=name, + data_type=data_type, + ) + + query_common_methods.additional_properties = d + return query_common_methods + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/query_status.py b/pachca_api/pachca_api_open_api_3_0_client/models/query_status.py new file mode 100644 index 0000000..885c9fc --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/query_status.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_status_status import QueryStatusStatus + + +T = TypeVar("T", bound="QueryStatus") + + +@_attrs_define +class QueryStatus: + """ + Attributes: + status (Union[Unset, QueryStatusStatus]): Собранный объект параметров нового статуса + """ + + status: Union[Unset, "QueryStatusStatus"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.status, Unset): + status = self.status.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if status is not UNSET: + field_dict["status"] = status + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_status_status import QueryStatusStatus + + d = src_dict.copy() + _status = d.pop("status", UNSET) + status: Union[Unset, QueryStatusStatus] + if isinstance(_status, Unset): + status = UNSET + else: + status = QueryStatusStatus.from_dict(_status) + + query_status = cls( + status=status, + ) + + query_status.additional_properties = d + return query_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/query_status_status.py b/pachca_api/pachca_api_open_api_3_0_client/models/query_status_status.py new file mode 100644 index 0000000..48858ea --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/query_status_status.py @@ -0,0 +1,102 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryStatusStatus") + + +@_attrs_define +class QueryStatusStatus: + """Собранный объект параметров нового статуса + + Attributes: + emoji (str): Emoji символ статуса + title (str): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ + """ + + emoji: str + title: str + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "emoji": emoji, + "title": title, + } + ) + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji") + + title = d.pop("title") + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + query_status_status = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + query_status_status.additional_properties = d + return query_status_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/reaction.py b/pachca_api/pachca_api_open_api_3_0_client/models/reaction.py new file mode 100644 index 0000000..de28f69 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/reaction.py @@ -0,0 +1,86 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Reaction") + + +@_attrs_define +class Reaction: + """ + Attributes: + user_id (Union[Unset, int]): Идентификатор пользователя, оставившего реакцию. + created_at (Union[Unset, datetime.datetime]): Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY- + MM-DDThh:mm:ss.sssZ. + code (Union[Unset, str]): Emoji символ реакции. + """ + + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + code: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if code is not UNSET: + field_dict["code"] = code + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + code = d.pop("code", UNSET) + + reaction = cls( + user_id=user_id, + created_at=created_at, + code=code, + ) + + reaction.additional_properties = d + return reaction + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/status_type_0.py b/pachca_api/pachca_api_open_api_3_0_client/models/status_type_0.py new file mode 100644 index 0000000..8997cfe --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/status_type_0.py @@ -0,0 +1,101 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="StatusType0") + + +@_attrs_define +class StatusType0: + """Статус. Возвращается как null, если статус не установлен. + + Attributes: + emoji (Union[Unset, str]): Emoji символ статуса + title (Union[Unset, str]): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + """ + + emoji: Union[Unset, str] = UNSET + title: Union[Unset, str] = UNSET + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if emoji is not UNSET: + field_dict["emoji"] = emoji + if title is not UNSET: + field_dict["title"] = title + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji", UNSET) + + title = d.pop("title", UNSET) + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + status_type_0 = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + status_type_0.additional_properties = d + return status_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/models/tag.py b/pachca_api/pachca_api_open_api_3_0_client/models/tag.py new file mode 100644 index 0000000..6504540 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/models/tag.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Tag") + + +@_attrs_define +class Tag: + """Для получения тега вам необходимо знать его id и указать его в URL запроса. + + Attributes: + id (Union[Unset, int]): Идентификатор тега + name (Union[Unset, str]): Название тега + users_count (Union[Unset, int]): Количество сотрудников, которые имеют этот тег + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + users_count: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + users_count = self.users_count + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if users_count is not UNSET: + field_dict["users_count"] = users_count + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + users_count = d.pop("users_count", UNSET) + + tag = cls( + id=id, + name=name, + users_count=users_count, + ) + + tag.additional_properties = d + return tag + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/pachca_api/pachca_api_open_api_3_0_client/py.typed b/pachca_api/pachca_api_open_api_3_0_client/py.typed new file mode 100644 index 0000000..1aad327 --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/pachca_api/pachca_api_open_api_3_0_client/types.py b/pachca_api/pachca_api_open_api_3_0_client/types.py new file mode 100644 index 0000000..b9ed58b --- /dev/null +++ b/pachca_api/pachca_api_open_api_3_0_client/types.py @@ -0,0 +1,46 @@ +"""Contains some shared types for properties""" + +from collections.abc import MutableMapping +from http import HTTPStatus +from typing import BinaryIO, Generic, Literal, Optional, TypeVar + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: Optional[str] = None + mime_type: Optional[str] = None + + def to_tuple(self) -> FileJsonType: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: Optional[T] + + +__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/pachca_api/pyproject.toml b/pachca_api/pyproject.toml new file mode 100644 index 0000000..29f8de8 --- /dev/null +++ b/pachca_api/pyproject.toml @@ -0,0 +1,27 @@ +[tool.poetry] +name = "pachca-api-open-api-3-0-client" +version = "3.0.3" +description = "A client library for accessing PachcaAPI - OpenAPI 3.0" +authors = [] +readme = "README.md" +packages = [ + {include = "pachca_api_open_api_3_0_client"}, +] +include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] + + +[tool.poetry.dependencies] +python = "^3.9" +httpx = ">=0.20.0,<0.28.0" +attrs = ">=21.3.0" +python-dateutil = "^2.8.0" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["F", "I", "UP"] diff --git a/templates_api/endpoint_macros.py.jinja b/templates_api/endpoint_macros.py.jinja new file mode 100644 index 0000000..2da580a --- /dev/null +++ b/templates_api/endpoint_macros.py.jinja @@ -0,0 +1,186 @@ +{% from "property_templates/helpers.jinja" import guarded_statement %} +{% from "helpers.jinja" import safe_docstring %} + +{% macro header_params(endpoint) %} +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} +headers: dict[str, Any] = {} +{% if endpoint.header_parameters %} + {% for parameter in endpoint.header_parameters %} + {% import "property_templates/" + parameter.template as param_template %} + {% if param_template.transform_header %} + {% set expression = param_template.transform_header(parameter.python_name) %} + {% else %} + {% set expression = parameter.python_name %} + {% endif %} + {% set statement = 'headers["' + parameter.name + '"]' + " = " + expression %} +{{ guarded_statement(parameter, parameter.python_name, statement) }} + {% endfor %} +{% endif %} +{% endif %} +{% endmacro %} + +{% macro cookie_params(endpoint) %} +{% if endpoint.cookie_parameters %} +cookies = {} + {% for parameter in endpoint.cookie_parameters %} + {% if parameter.required %} +cookies["{{ parameter.name}}"] = {{ parameter.python_name }} + {% else %} +if {{ parameter.python_name }} is not UNSET: + cookies["{{ parameter.name}}"] = {{ parameter.python_name }} + {% endif %} + + {% endfor %} +{% endif %} +{% endmacro %} + + +{% macro query_params(endpoint) %} +{% if endpoint.query_parameters %} +params: dict[str, Any] = {} + +{% for property in endpoint.query_parameters %} + {% set destination = property.python_name %} + {% import "property_templates/" + property.template as prop_template %} + {% if prop_template.transform %} + {% set destination = "json_" + property.python_name %} +{{ prop_template.transform(property, property.python_name, destination) }} + {% endif %} + {%- if not property.json_is_dict %} +params["{{ property.name }}"] = {{ destination }} + {% else %} +{{ guarded_statement(property, destination, "params.update(" + destination + ")") }} + {% endif %} + +{% endfor %} + +params = {k: v for k, v in params.items() if v is not UNSET and v is not None} +{% endif %} +{% endmacro %} + +{% macro body_to_kwarg(body, destination) %} +{% if body.body_type == "data" %} +{{ destination }} = body.to_dict() +{% elif body.body_type == "files"%} +{{ multipart_body(body, destination) }} +{% elif body.body_type == "json" %} +{{ json_body(body, destination) }} +{% elif body.body_type == "content" %} +{{ destination }} = body.payload +{% endif %} +{% endmacro %} + +{% macro json_body(body, destination) %} +{% set property = body.prop %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform %} +{{ prop_template.transform(property, property.python_name, destination) }} +{% else %} +{{ destination }} = {{ property.python_name }} +{% endif %} +{% endmacro %} + +{% macro multipart_body(body, destination) %} +{% set property = body.prop %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform_multipart_body %} +{{ prop_template.transform_multipart_body(property, property.python_name, destination) }} +{% endif %} +{% endmacro %} + +{# The all the kwargs passed into an endpoint (and variants thereof)) #} +{% macro arguments(endpoint, include_client=True) %} +{# path parameters #} +{% for parameter in endpoint.path_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{% if include_client or ((endpoint.list_all_parameters() | length) > (endpoint.path_parameters | length)) %} +*, +{% endif %} +{# Proper client based on whether or not the endpoint requires authentication #} +{% if include_client %} +{% if endpoint.requires_security %} +client: AuthenticatedClient, +{% else %} +client: Union[AuthenticatedClient, Client], +{% endif %} +{% endif %} +{# Any allowed bodies #} +{% if endpoint.bodies | length == 1 %} +body: {{ endpoint.bodies[0].prop.get_type_string() }}, +{% elif endpoint.bodies | length > 1 %} +body: Union[ + {% for body in endpoint.bodies %} + {{ body.prop.get_type_string() }}, + {% endfor %} +], +{% endif %} +{# query parameters #} +{% for parameter in endpoint.query_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{% for parameter in endpoint.header_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{# cookie parameters #} +{% for parameter in endpoint.cookie_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{% endmacro %} + +{# Just lists all kwargs to endpoints as name=name for passing to other functions #} +{% macro kwargs(endpoint, include_client=True) %} +{% for parameter in endpoint.path_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% if include_client %} +client=client, +{% endif %} +{% if endpoint.bodies | length > 0 %} +body=body, +{% endif %} +{% for parameter in endpoint.query_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% for parameter in endpoint.header_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% for parameter in endpoint.cookie_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% endmacro %} + +{% macro docstring_content(endpoint, return_string, is_detailed) %} +{% if endpoint.summary %}{{ endpoint.summary | wordwrap(100)}} + +{% endif -%} +{%- if endpoint.description %} {{ endpoint.description | wordwrap(100) }} + +{% endif %} +{% if not endpoint.summary and not endpoint.description %} +{# Leave extra space so that Args or Returns isn't at the top #} + +{% endif %} +{% set all_parameters = endpoint.list_all_parameters() %} +{% if all_parameters %} +Args: + {% for parameter in all_parameters %} + {{ parameter.to_docstring() | wordwrap(90) | indent(8) }} + {% endfor %} + +{% endif %} +Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + +Returns: +{% if is_detailed %} + Response[{{ return_string }}] +{% else %} + {{ return_string }} +{% endif %} +{% endmacro %} + +{% macro docstring(endpoint, return_string, is_detailed) %} +{{ safe_docstring(docstring_content(endpoint, return_string, is_detailed)) }} +{% endmacro %} diff --git a/templates_api/endpoint_module_api.py.jinja b/templates_api/endpoint_module_api.py.jinja new file mode 100644 index 0000000..16bfa4a --- /dev/null +++ b/templates_api/endpoint_module_api.py.jinja @@ -0,0 +1,527 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ...client import AuthenticatedClient, Client +from ...types import Response, UNSET +from ... import errors + +{% for relative in endpoint.relative_imports | sort %} +{{ relative }} +{% endfor %} + +{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, + arguments, client, kwargs, parse_response, docstring, body_to_kwarg %} + +{% set return_string = endpoint.response_type() %} + +# Основной объект Pachca +class Pachca: + def __init__(self, token: str): + """ + Инициализация объекта Pachca с токеном авторизации. + + :param token: Токен авторизации для доступа к API. + """ + self.token = token + + {% for operation in endpoint.operations %} + async def {{ operation.operation_id }}(self, + {{ arguments(operation) | indent(8) }}): + """ + {{ operation.summary }} + + {{ operation.description }} + + :param {{ operation.parameters | join(", ") }}: Входные параметры. + :param page: Номер страницы для выборки (по умолчанию 1). + :param query: Поисковая фраза для фильтрации результатов. + :raises errors.ApiError: В случае ошибки API. + :return: Объект, соответствующий схеме ответа. + """ + kwargs = _get_kwargs( + {{ arguments(operation, include_client=False) | indent(12) }} + ) + + async with httpx.AsyncClient() as client: + response = await client.request(**kwargs) + + # Обработка ответа + return parse_response(response) + + {% endfor %} + +def _get_kwargs( + {{ arguments(endpoint, include_client=False) | indent(4) }} +) -> dict[str, Any]: + {{ header_params(endpoint) | indent(4) }} + + {{ cookie_params(endpoint) | indent(4) }} + + {{ query_params(endpoint) | indent(4) }} + + _kwargs: dict[str, Any] = { + "method": "{{ endpoint.method }}", + {% if endpoint.path_parameters %} + "url": "{{ endpoint.path }}".format( + {%- for parameter in endpoint.path_parameters -%} + {{parameter.python_name}}={{parameter.python_name}}, + {%- endfor -%} + ), + {% else %} + "url": "{{ endpoint.path }}", + {% endif %} + {% if endpoint.query_parameters %} + "params": params, + {% endif %} + {% if endpoint.cookie_parameters %} + "cookies": cookies, + {% endif %} + } + +{% if endpoint.bodies | length > 1 %} +{% for body in endpoint.bodies %} + if isinstance(body, {{body.prop.get_type_string() }}): + {% set destination = "_" + body.body_type + "_body" %} + {{ body_to_kwarg(body, destination) | indent(8) }} + _kwargs["{{ body.body_type.value }}"] = {{ destination }} + headers["Content-Type"] = "{{ body.content_type }}" +{% endfor %} +{% elif endpoint.bodies | length == 1 %} +{% set body = endpoint.bodies[0] %} + {{ body_to_kwarg(body, "_body") | indent(4) }} + _kwargs["{{ body.body_type.value }}"] = _body + {% if body.content_type != "multipart/form-data" %}{# Need httpx to set the boundary automatically #} + headers["Content-Type"] = "{{ body.content_type }}" + {% endif %} +{% endif %} + +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} + _kwargs["headers"] = headers +{% endif %} + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[{{ return_string }}]: + {% for response in endpoint.responses %} + if response.status_code == {{ response.status_code.value }}: + {% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %} + {% if prop_template.construct %} + {{ prop_template.construct(response.prop, response.source.attribute) | indent(8) }} + {% elif response.source.return_type == response.prop.get_type_string() %} + {{ response.prop.python_name }} = {{ response.source.attribute }} + {% else %} + {{ response.prop.python_name }} = cast({{ response.prop.get_type_string() }}, {{ response.source.attribute }}) + {% endif %} + return {{ response.prop.python_name }} + {% else %} + return None + {% endif %} + {% endfor %} + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[{{ return_string }}]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + {{ arguments(endpoint) | indent(4) }} +) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = _get_kwargs( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + +{% if parsed_responses %} +def sync( + {{ arguments(endpoint) | indent(4) }} +) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return sync_detailed( + {{ kwargs(endpoint) }} + ).parsed +{% endif %} + +async def asyncio_detailed( + {{ arguments(endpoint) | indent(4) }} +) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = _get_kwargs( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = await client.get_async_httpx_client().request( + **kwargs + ) + + return _build_response(client=client, response=response) + +{% if parsed_responses %} +async def asyncio( + {{ arguments(endpoint) | indent(4) }} +) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return (await asyncio_detailed( + {{ kwargs(endpoint) }} + )).parsed +{% endif %} + + + + + + + + + + + + + +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ...client import AuthenticatedClient, Client +from ...types import Response, UNSET +from ... import errors + +{% for relative in endpoint.relative_imports | sort %} +{{ relative }} +{% endfor %} + +{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, + arguments, client, kwargs, parse_response, docstring, body_to_kwarg %} + +{% set return_string = endpoint.response_type() %} +{% set parsed_responses = (endpoint.responses | length > 0) and return_string != "Any" %} + +def _get_kwargs( + {{ arguments(endpoint, include_client=False) | indent(4) }} +) -> dict[str, Any]: + {{ header_params(endpoint) | indent(4) }} + + {{ cookie_params(endpoint) | indent(4) }} + + {{ query_params(endpoint) | indent(4) }} + + _kwargs: dict[str, Any] = { + "method": "{{ endpoint.method }}", + {% if endpoint.path_parameters %} + "url": "{{ endpoint.path }}".format( + {%- for parameter in endpoint.path_parameters -%} + {{parameter.python_name}}={{parameter.python_name}}, + {%- endfor -%} + ), + {% else %} + "url": "{{ endpoint.path }}", + {% endif %} + {% if endpoint.query_parameters %} + "params": params, + {% endif %} + {% if endpoint.cookie_parameters %} + "cookies": cookies, + {% endif %} + } + +{% if endpoint.bodies | length > 1 %} +{% for body in endpoint.bodies %} + if isinstance(body, {{body.prop.get_type_string() }}): + {% set destination = "_" + body.body_type + "_body" %} + {{ body_to_kwarg(body, destination) | indent(8) }} + _kwargs["{{ body.body_type.value }}"] = {{ destination }} + headers["Content-Type"] = "{{ body.content_type }}" +{% endfor %} +{% elif endpoint.bodies | length == 1 %} +{% set body = endpoint.bodies[0] %} + {{ body_to_kwarg(body, "_body") | indent(4) }} + _kwargs["{{ body.body_type.value }}"] = _body + {% if body.content_type != "multipart/form-data" %}{# Need httpx to set the boundary automatically #} + headers["Content-Type"] = "{{ body.content_type }}" + {% endif %} +{% endif %} + +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} + _kwargs["headers"] = headers +{% endif %} + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[{{ return_string }}]: + {% for response in endpoint.responses %} + if response.status_code == {{ response.status_code.value }}: + {% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %} + {% if prop_template.construct %} + {{ prop_template.construct(response.prop, response.source.attribute) | indent(8) }} + {% elif response.source.return_type == response.prop.get_type_string() %} + {{ response.prop.python_name }} = {{ response.source.attribute }} + {% else %} + {{ response.prop.python_name }} = cast({{ response.prop.get_type_string() }}, {{ response.source.attribute }}) + {% endif %} + return {{ response.prop.python_name }} + {% else %} + return None + {% endif %} + {% endfor %} + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[{{ return_string }}]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + {{ arguments(endpoint) | indent(4) }} +) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = _get_kwargs( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + +{% if parsed_responses %} +def sync( + {{ arguments(endpoint) | indent(4) }} +) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return sync_detailed( + {{ kwargs(endpoint) }} + ).parsed +{% endif %} + +async def asyncio_detailed( + {{ arguments(endpoint) | indent(4) }} +) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = _get_kwargs( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = await client.get_async_httpx_client().request( + **kwargs + ) + + return _build_response(client=client, response=response) + +{% if parsed_responses %} +async def asyncio( + {{ arguments(endpoint) | indent(4) }} +) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return (await asyncio_detailed( + {{ kwargs(endpoint) }} + )).parsed +{% endif %} + + + + + + + + + + + +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ...client import AuthenticatedClient, Client +from ...types import Response, UNSET +from ... import errors + +{% for relative in endpoint.relative_imports | sort %} +{{ relative }} +{% endfor %} + +{% from "endpoint_macros.py.jinja" import header_params, cookie_params, query_params, + arguments, client, kwargs, parse_response, docstring, body_to_kwarg %} + +{% set return_string = endpoint.response_type() %} +# Основной объект Pachca +class Pachca: + def __init__(self, token: str): + """ + Инициализация объекта Pachca с токеном авторизации. + + :param token: Токен авторизации для доступа к API. + """ + self.token = token + + def _get_kwargs( + self, + {{ arguments(endpoint, include_client=False) | indent(4) }} + ) -> dict[str, Any]: + {{ header_params(endpoint) | indent(4) }} + + {{ cookie_params(endpoint) | indent(4) }} + + {{ query_params(endpoint) | indent(4) }} + + _kwargs: dict[str, Any] = { + "method": "{{ endpoint.method }}", + {% if endpoint.path_parameters %} + "url": "{{ endpoint.path }}".format( + {%- for parameter in endpoint.path_parameters -%} + {{parameter.python_name}}={{parameter.python_name}}, + {%- endfor -%} + ), + {% else %} + "url": "{{ endpoint.path }}", + {% endif %} + {% if endpoint.query_parameters %} + "params": params, + {% endif %} + {% if endpoint.cookie_parameters %} + "cookies": cookies, + {% endif %} + } + + {% if endpoint.bodies | length > 1 %} + {% for body in endpoint.bodies %} + if isinstance(body, {{body.prop.get_type_string() }}): + {% set destination = "_" + body.body_type + "_body" %} + {{ body_to_kwarg(body, destination) | indent(8) }} + _kwargs["{{ body.body_type.value }}"] = {{ destination }} + headers["Content-Type"] = "{{ body.content_type }}" + {% endfor %} + {% elif endpoint.bodies | length == 1 %} + {% set body = endpoint.bodies[0] %} + {{ body_to_kwarg(body, "_body") | indent(4) }} + _kwargs["{{ body.body_type.value }}"] = _body + {% if body.content_type != "multipart/form-data" %}{# Need httpx to set the boundary automatically #} + headers["Content-Type"] = "{{ body.content_type }}" + {% endif %} + {% endif %} + + {% if endpoint.header_parameters or endpoint.bodies | length > 0 %} + _kwargs["headers"] = headers + {% endif %} + return _kwargs + + + def _parse_response(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[{{ return_string }}]: + {% for response in endpoint.responses %} + if response.status_code == {{ response.status_code.value }}: + {% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %} + {% if prop_template.construct %} + {{ prop_template.construct(response.prop, response.source.attribute) | indent(8) }} + {% elif response.source.return_type == response.prop.get_type_string() %} + {{ response.prop.python_name }} = {{ response.source.attribute }} + {% else %} + {{ response.prop.python_name }} = cast({{ response.prop.get_type_string() }}, {{ response.source.attribute }}) + {% endif %} + return {{ response.prop.python_name }} + {% else %} + return None + {% endif %} + {% endfor %} + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + + def _build_response(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[{{ return_string }}]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response(client=client, response=response), + ) + + + def sync_detailed( + self, + {{ arguments(endpoint) | indent(4) }} + ) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = self._get_kwargs( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return self._build_response(client=client, response=response) + + {% if parsed_responses %} + def sync( + self, + {{ arguments(endpoint) | indent(4) }} + ) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return self.sync_detailed( + {{ kwargs(endpoint) }} + ).parsed + {% endif %} + + async def asyncio_detailed( + self, + {{ arguments(endpoint) | indent(4) }} + ) -> Response[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} + + kwargs = self._get_kwargs( + {{ kwargs(endpoint, include_client=False) }} + ) + + response = await client.get_async_httpx_client().request( + **kwargs + ) + + return self._build_response(client=client, response=response) + + {% if parsed_responses %} + async def asyncio( + self, {{ arguments(endpoint) | indent(4) }} + ) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + + return (await self.asyncio_detailed( + {{ kwargs(endpoint) }} + )).parsed + {% endif %} From 4a94a1bc71946ca07cfafb7a9d6896a4630ea95b Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 25 Dec 2024 18:42:01 +0300 Subject: [PATCH 077/296] added self and corrected client generate --- .../api/chats_and_channels/create_chat.py | 19 +- .../api/chats_and_channels/get_chat.py | 22 +- .../api/chats_and_channels/get_chats.py | 19 +- .../api/comments/create_thread.py | 18 +- .../api/common_methods/get_common_methods.py | 19 +- .../api/common_methods/get_direct_url.py | 22 +- .../api/common_methods/get_uploads.py | 29 +- .../api/employees/get_employee.py | 22 +- .../api/employees/get_employees.py | 23 +- .../api/messages/create_message.py | 19 +- .../api/messages/get_list_message.py | 19 +- .../api/messages/get_message.py | 22 +- .../api/messages/put_messages_id.py | 19 +- .../delete_message_reactions.py | 19 +- .../get_message_reactions.py | 19 +- .../post_message_reactions.py | 19 +- .../api/reminders/post_tasks.py | 19 +- .../api/status/del_status.py | 21 +- .../api/status/get_status.py | 29 +- .../api/status/put_status.py | 23 +- .../api/tags/get_tag.py | 22 +- .../api/tags/get_tags.py | 23 +- .../api/tags/get_tags_employees.py | 19 +- .../delete_chats_id_leave.py | 22 +- .../post_members_to_chats.py | 23 +- .../post_tags_to_chats.py | 23 +- .../pachca_api_open_api_3_0_client/client.py | 1823 ++++++++--------- pachca-api-open-api-3-0-client/pyproject.toml | 4 +- pachca.py | 19 +- script.py | 7 +- templates/client.py.jinja | 3 +- templates/endpoint_macros.py.jinja | 174 ++ templates/endpoint_module.py.jinja | 12 +- 33 files changed, 1272 insertions(+), 1323 deletions(-) create mode 100644 templates/endpoint_macros.py.jinja diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py index c9af29a..aad296e 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.create_chat_body import CreateChatBody from ...models.create_chat_response_201 import CreateChatResponse201 from ...models.create_chat_response_400 import CreateChatResponse400 @@ -15,7 +14,6 @@ def _get_kwargs_createChat( self, - *, body: CreateChatBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -35,7 +33,7 @@ def _get_kwargs_createChat( def _parse_response_createChat( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: if response.status_code == 201: response_201 = CreateChatResponse201.from_dict(response.json()) @@ -53,27 +51,25 @@ def _parse_response_createChat( response_422 = CreateChatResponse422.from_dict(response.json()) return response_422 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_createChat( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_createChat(client=client, response=response), + parsed=self._parse_response_createChat(response=response), ) async def asyncio_detailed_createChat( self, - *, - client: Union[AuthenticatedClient, Client], body: CreateChatBody, ) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: r""" Новая беседа или канал @@ -96,15 +92,13 @@ async def asyncio_detailed_createChat( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(client=client, response=response) + return self._build_response_createChat(response=response) async def createChat( self, - *, - client: Union[AuthenticatedClient, Client], body: CreateChatBody, ) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: r""" Новая беседа или канал @@ -125,7 +119,6 @@ async def createChat( return ( await self.asyncio_detailed_createChat( - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py index 1bbce3f..88b08c1 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_chat_response_200 import GetChatResponse200 from ...models.get_chat_response_404 import GetChatResponse404 from ...types import Response @@ -22,9 +21,7 @@ def _get_kwargs_getChat( return _kwargs -def _parse_response_getChat( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: +def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: if response.status_code == 200: response_200 = GetChatResponse200.from_dict(response.json()) @@ -33,28 +30,24 @@ def _parse_response_getChat( response_404 = GetChatResponse404.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getChat( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[GetChatResponse200, GetChatResponse404]]: +def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getChat(client=client, response=response), + parsed=self._parse_response_getChat(response=response), ) async def asyncio_detailed_getChat( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Union[GetChatResponse200, GetChatResponse404]]: """Информация о беседе или канале @@ -76,16 +69,14 @@ async def asyncio_detailed_getChat( id=id, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(client=client, response=response) + return self._build_response_getChat(response=response) async def getChat( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: """Информация о беседе или канале @@ -106,6 +97,5 @@ async def getChat( return ( await self.asyncio_detailed_getChat( id=id, - client=client, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py index 2cffea1..182e112 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -5,7 +5,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_chats_availability import GetChatsAvailability from ...models.get_chats_response_200 import GetChatsResponse200 from ...models.get_chats_response_400 import GetChatsResponse400 @@ -17,7 +16,6 @@ def _get_kwargs_getChats( self, - *, sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, @@ -65,7 +63,7 @@ def _get_kwargs_getChats( def _parse_response_getChats( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: if response.status_code == 200: response_200 = GetChatsResponse200.from_dict(response.json()) @@ -83,27 +81,25 @@ def _parse_response_getChats( response_422 = GetChatsResponse422.from_dict(response.json()) return response_422 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_getChats( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getChats(client=client, response=response), + parsed=self._parse_response_getChats(response=response), ) async def asyncio_detailed_getChats( self, - *, - client: Union[AuthenticatedClient, Client], sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, @@ -141,15 +137,13 @@ async def asyncio_detailed_getChats( last_message_at_before=last_message_at_before, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(client=client, response=response) + return self._build_response_getChats(response=response) async def getChats( self, - *, - client: Union[AuthenticatedClient, Client], sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, @@ -180,7 +174,6 @@ async def getChats( return ( await self.asyncio_detailed_getChats( - client=client, sortid=sortid, per=per, page=page, diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py index 216931b..affccc4 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.create_thread_response_200 import CreateThreadResponse200 from ...models.not_found import NotFound @@ -24,7 +23,7 @@ def _get_kwargs_createThread( def _parse_response_createThread( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: if response.status_code == 200: response_200 = CreateThreadResponse200.from_dict(response.json()) @@ -38,28 +37,26 @@ def _parse_response_createThread( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_createThread( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_createThread(client=client, response=response), + parsed=self._parse_response_createThread(response=response), ) async def asyncio_detailed_createThread( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: """Создание нового треда @@ -81,16 +78,14 @@ async def asyncio_detailed_createThread( id=id, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(client=client, response=response) + return self._build_response_createThread(response=response) async def createThread( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: """Создание нового треда @@ -111,6 +106,5 @@ async def createThread( return ( await self.asyncio_detailed_createThread( id=id, - client=client, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py index aaa0a23..f26f8cc 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 from ...types import UNSET, Response @@ -12,7 +11,6 @@ def _get_kwargs_getCommonMethods( self, - *, entity_type: str, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -31,7 +29,7 @@ def _get_kwargs_getCommonMethods( def _parse_response_getCommonMethods( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: if response.status_code == 200: response_200 = GetCommonMethodsResponse200.from_dict(response.json()) @@ -41,27 +39,25 @@ def _parse_response_getCommonMethods( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_getCommonMethods( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getCommonMethods(client=client, response=response), + parsed=self._parse_response_getCommonMethods(response=response), ) async def asyncio_detailed_getCommonMethods( self, - *, - client: Union[AuthenticatedClient, Client], entity_type: str, ) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: """Список дополнительных полей @@ -84,15 +80,13 @@ async def asyncio_detailed_getCommonMethods( entity_type=entity_type, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(client=client, response=response) + return self._build_response_getCommonMethods(response=response) async def getCommonMethods( self, - *, - client: Union[AuthenticatedClient, Client], entity_type: str, ) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: """Список дополнительных полей @@ -113,7 +107,6 @@ async def getCommonMethods( return ( await self.asyncio_detailed_getCommonMethods( - client=client, entity_type=entity_type, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py index f2d565b..5124a72 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py @@ -1,17 +1,15 @@ from http import HTTPStatus -from typing import Any, Optional, Union +from typing import Any, Optional import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.direct_response import DirectResponse from ...types import Response def _get_kwargs_getDirectUrl( self, - *, body: DirectResponse, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -29,32 +27,26 @@ def _get_kwargs_getDirectUrl( return _kwargs -def _parse_response_getDirectUrl( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Any]: +def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: if response.status_code == 204: return None - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getDirectUrl( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Any]: +def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getDirectUrl(client=client, response=response), + parsed=self._parse_response_getDirectUrl(response=response), ) async def asyncio_detailed_getDirectUrl( self, - *, - client: Union[AuthenticatedClient, Client], body: DirectResponse, ) -> Response[Any]: """Получение URL для загрузки @@ -76,6 +68,6 @@ async def asyncio_detailed_getDirectUrl( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getDirectUrl(client=client, response=response) + return self._build_response_getDirectUrl(response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py index f5f9d45..eb3f137 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -1,10 +1,9 @@ from http import HTTPStatus -from typing import Any, Optional, Union +from typing import Any, Optional import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.file_response import FileResponse from ...types import Response @@ -20,34 +19,28 @@ def _get_kwargs_getUploads( return _kwargs -def _parse_response_getUploads( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[FileResponse]: +def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: if response.status_code == 200: response_200 = FileResponse.from_dict(response.json()) return response_200 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getUploads( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[FileResponse]: +def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getUploads(client=client, response=response), + parsed=self._parse_response_getUploads(response=response), ) async def asyncio_detailed_getUploads( self, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[FileResponse]: """Получение подписи и ключа для загрузки файла @@ -63,15 +56,13 @@ async def asyncio_detailed_getUploads( kwargs = self._get_kwargs_getUploads() - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getUploads(client=client, response=response) + return self._build_response_getUploads(response=response) async def getUploads( self, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[FileResponse]: """Получение подписи и ключа для загрузки файла @@ -85,8 +76,4 @@ async def getUploads( FileResponse """ - return ( - await self.asyncio_detailed_getUploads( - client=client, - ) - ).parsed + return (await self.asyncio_detailed_getUploads()).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py index 5e1d455..98327ba 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_employee_response_200 import GetEmployeeResponse200 from ...models.not_found import NotFound from ...types import Response @@ -22,9 +21,7 @@ def _get_kwargs_getEmployee( return _kwargs -def _parse_response_getEmployee( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[GetEmployeeResponse200, NotFound]]: +def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: if response.status_code == 200: response_200 = GetEmployeeResponse200.from_dict(response.json()) @@ -33,28 +30,24 @@ def _parse_response_getEmployee( response_404 = NotFound.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getEmployee( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[GetEmployeeResponse200, NotFound]]: +def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getEmployee(client=client, response=response), + parsed=self._parse_response_getEmployee(response=response), ) async def asyncio_detailed_getEmployee( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Union[GetEmployeeResponse200, NotFound]]: """получение информации о сотруднике @@ -76,16 +69,14 @@ async def asyncio_detailed_getEmployee( id=id, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(client=client, response=response) + return self._build_response_getEmployee(response=response) async def getEmployee( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[Union[GetEmployeeResponse200, NotFound]]: """получение информации о сотруднике @@ -106,6 +97,5 @@ async def getEmployee( return ( await self.asyncio_detailed_getEmployee( id=id, - client=client, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py index bd150e1..efcbab5 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -4,14 +4,12 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_employees_response_200 import GetEmployeesResponse200 from ...types import UNSET, Response, Unset def _get_kwargs_getEmployees( self, - *, per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, query: Union[Unset, str] = UNSET, @@ -35,34 +33,28 @@ def _get_kwargs_getEmployees( return _kwargs -def _parse_response_getEmployees( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[GetEmployeesResponse200]: +def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: if response.status_code == 200: response_200 = GetEmployeesResponse200.from_dict(response.json()) return response_200 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getEmployees( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[GetEmployeesResponse200]: +def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getEmployees(client=client, response=response), + parsed=self._parse_response_getEmployees(response=response), ) async def asyncio_detailed_getEmployees( self, - *, - client: Union[AuthenticatedClient, Client], per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, query: Union[Unset, str] = UNSET, @@ -90,15 +82,13 @@ async def asyncio_detailed_getEmployees( query=query, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(client=client, response=response) + return self._build_response_getEmployees(response=response) async def getEmployees( self, - *, - client: Union[AuthenticatedClient, Client], per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, query: Union[Unset, str] = UNSET, @@ -122,7 +112,6 @@ async def getEmployees( return ( await self.asyncio_detailed_getEmployees( - client=client, per=per, page=page, query=query, diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py index 75991f6..48c4388 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.create_message_body import CreateMessageBody from ...models.create_message_response_201 import CreateMessageResponse201 @@ -14,7 +13,6 @@ def _get_kwargs_createMessage( self, - *, body: CreateMessageBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -34,7 +32,7 @@ def _get_kwargs_createMessage( def _parse_response_createMessage( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: if response.status_code == 201: response_201 = CreateMessageResponse201.from_dict(response.json()) @@ -53,27 +51,25 @@ def _parse_response_createMessage( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_createMessage( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_createMessage(client=client, response=response), + parsed=self._parse_response_createMessage(response=response), ) async def asyncio_detailed_createMessage( self, - *, - client: Union[AuthenticatedClient, Client], body: CreateMessageBody, ) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: r"""создание нового сообщения @@ -107,15 +103,13 @@ async def asyncio_detailed_createMessage( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createMessage(client=client, response=response) + return self._build_response_createMessage(response=response) async def createMessage( self, - *, - client: Union[AuthenticatedClient, Client], body: CreateMessageBody, ) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: r"""создание нового сообщения @@ -147,7 +141,6 @@ async def createMessage( return ( await self.asyncio_detailed_createMessage( - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py index cd3cc22..64487d6 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.get_list_message_response_200 import GetListMessageResponse200 from ...models.not_found import NotFound @@ -13,7 +12,6 @@ def _get_kwargs_getListMessage( self, - *, chat_id: int, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, @@ -38,7 +36,7 @@ def _get_kwargs_getListMessage( def _parse_response_getListMessage( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: if response.status_code == 200: response_200 = GetListMessageResponse200.from_dict(response.json()) @@ -52,27 +50,25 @@ def _parse_response_getListMessage( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_getListMessage( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getListMessage(client=client, response=response), + parsed=self._parse_response_getListMessage(response=response), ) async def asyncio_detailed_getListMessage( self, - *, - client: Union[AuthenticatedClient, Client], chat_id: int, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, @@ -105,15 +101,13 @@ async def asyncio_detailed_getListMessage( page=page, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getListMessage(client=client, response=response) + return self._build_response_getListMessage(response=response) async def getListMessage( self, - *, - client: Union[AuthenticatedClient, Client], chat_id: int, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, @@ -142,7 +136,6 @@ async def getListMessage( return ( await self.asyncio_detailed_getListMessage( - client=client, chat_id=chat_id, per=per, page=page, diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py index 65fe729..6f2ec30 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_message_response_200 import GetMessageResponse200 from ...models.not_found import NotFound from ...types import Response @@ -22,9 +21,7 @@ def _get_kwargs_getMessage( return _kwargs -def _parse_response_getMessage( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[GetMessageResponse200, NotFound]]: +def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: if response.status_code == 200: response_200 = GetMessageResponse200.from_dict(response.json()) @@ -33,28 +30,24 @@ def _parse_response_getMessage( response_404 = NotFound.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getMessage( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[GetMessageResponse200, NotFound]]: +def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getMessage(client=client, response=response), + parsed=self._parse_response_getMessage(response=response), ) async def asyncio_detailed_getMessage( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Union[GetMessageResponse200, NotFound]]: """получение информации о сообщении @@ -77,16 +70,14 @@ async def asyncio_detailed_getMessage( id=id, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(client=client, response=response) + return self._build_response_getMessage(response=response) async def getMessage( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[Union[GetMessageResponse200, NotFound]]: """получение информации о сообщении @@ -108,6 +99,5 @@ async def getMessage( return ( await self.asyncio_detailed_getMessage( id=id, - client=client, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py index f2d63c9..0de0ea1 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.errors_code import ErrorsCode from ...models.put_messages_id_body import PutMessagesIdBody from ...models.put_messages_id_response_200 import PutMessagesIdResponse200 @@ -14,7 +13,6 @@ def _get_kwargs_put_messages_id( self, id: int, - *, body: PutMessagesIdBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -34,7 +32,7 @@ def _get_kwargs_put_messages_id( def _parse_response_put_messages_id( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: if response.status_code == 200: response_200 = PutMessagesIdResponse200.from_dict(response.json()) @@ -58,28 +56,26 @@ def _parse_response_put_messages_id( response_404.append(response_404_item) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_put_messages_id( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_put_messages_id(client=client, response=response), + parsed=self._parse_response_put_messages_id(response=response), ) async def asyncio_detailed_put_messages_id( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: PutMessagesIdBody, ) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: """Редактирование сообщения @@ -103,16 +99,14 @@ async def asyncio_detailed_put_messages_id( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(client=client, response=response) + return self._build_response_put_messages_id(response=response) async def put_messages_id( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: PutMessagesIdBody, ) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: """Редактирование сообщения @@ -134,7 +128,6 @@ async def put_messages_id( return ( await self.asyncio_detailed_put_messages_id( id=id, - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py index 3fa196b..cb9aef6 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 from ...types import UNSET, Response @@ -13,7 +12,6 @@ def _get_kwargs_deleteMessageReactions( self, id: str, - *, code: str, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -32,7 +30,7 @@ def _get_kwargs_deleteMessageReactions( def _parse_response_deleteMessageReactions( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: if response.status_code == 204: response_204 = cast(Any, None) @@ -45,28 +43,26 @@ def _parse_response_deleteMessageReactions( response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_deleteMessageReactions( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_deleteMessageReactions(client=client, response=response), + parsed=self._parse_response_deleteMessageReactions(response=response), ) async def asyncio_detailed_deleteMessageReactions( self, id: str, - *, - client: Union[AuthenticatedClient, Client], code: str, ) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: """Удаление реакции @@ -91,16 +87,14 @@ async def asyncio_detailed_deleteMessageReactions( code=code, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(client=client, response=response) + return self._build_response_deleteMessageReactions(response=response) async def deleteMessageReactions( self, id: str, - *, - client: Union[AuthenticatedClient, Client], code: str, ) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: """Удаление реакции @@ -123,7 +117,6 @@ async def deleteMessageReactions( return ( await self.asyncio_detailed_deleteMessageReactions( id=id, - client=client, code=code, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py index 5e9c982..4e11ad7 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.get_message_reactions_body import GetMessageReactionsBody from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 @@ -15,7 +14,6 @@ def _get_kwargs_getMessageReactions( self, id: int, - *, body: GetMessageReactionsBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -35,7 +33,7 @@ def _get_kwargs_getMessageReactions( def _parse_response_getMessageReactions( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: if response.status_code == 200: response_200 = GetMessageReactionsResponse200.from_dict(response.json()) @@ -49,28 +47,26 @@ def _parse_response_getMessageReactions( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_getMessageReactions( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getMessageReactions(client=client, response=response), + parsed=self._parse_response_getMessageReactions(response=response), ) async def asyncio_detailed_getMessageReactions( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: GetMessageReactionsBody, ) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: """Получение актуального списка реакций. @@ -95,16 +91,14 @@ async def asyncio_detailed_getMessageReactions( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(client=client, response=response) + return self._build_response_getMessageReactions(response=response) async def getMessageReactions( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: GetMessageReactionsBody, ) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: """Получение актуального списка реакций. @@ -127,7 +121,6 @@ async def getMessageReactions( return ( await self.asyncio_detailed_getMessageReactions( id=id, - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py index 3703d72..d37f812 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.post_message_reactions_body import PostMessageReactionsBody from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 @@ -15,7 +14,6 @@ def _get_kwargs_postMessageReactions( self, id: str, - *, body: PostMessageReactionsBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -35,7 +33,7 @@ def _get_kwargs_postMessageReactions( def _parse_response_postMessageReactions( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] ]: @@ -54,14 +52,14 @@ def _parse_response_postMessageReactions( response_404 = PostMessageReactionsResponse404.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_postMessageReactions( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] ]: @@ -69,15 +67,13 @@ def _build_response_postMessageReactions( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_postMessageReactions(client=client, response=response), + parsed=self._parse_response_postMessageReactions(response=response), ) async def asyncio_detailed_postMessageReactions( self, id: str, - *, - client: Union[AuthenticatedClient, Client], body: PostMessageReactionsBody, ) -> Response[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] @@ -105,16 +101,14 @@ async def asyncio_detailed_postMessageReactions( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(client=client, response=response) + return self._build_response_postMessageReactions(response=response) async def postMessageReactions( self, id: str, - *, - client: Union[AuthenticatedClient, Client], body: PostMessageReactionsBody, ) -> Optional[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] @@ -140,7 +134,6 @@ async def postMessageReactions( return ( await self.asyncio_detailed_postMessageReactions( id=id, - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py index ff76591..b689520 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.post_tasks_body import PostTasksBody from ...models.post_tasks_response_201 import PostTasksResponse201 from ...models.post_tasks_response_400 import PostTasksResponse400 @@ -13,7 +12,6 @@ def _get_kwargs_post_tasks( self, - *, body: PostTasksBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -33,7 +31,7 @@ def _get_kwargs_post_tasks( def _parse_response_post_tasks( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: if response.status_code == 201: response_201 = PostTasksResponse201.from_dict(response.json()) @@ -43,27 +41,25 @@ def _parse_response_post_tasks( response_400 = PostTasksResponse400.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_post_tasks( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_post_tasks(client=client, response=response), + parsed=self._parse_response_post_tasks(response=response), ) async def asyncio_detailed_post_tasks( self, - *, - client: Union[AuthenticatedClient, Client], body: PostTasksBody, ) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: """Метод для создания нового напоминания. @@ -90,15 +86,13 @@ async def asyncio_detailed_post_tasks( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(client=client, response=response) + return self._build_response_post_tasks(response=response) async def post_tasks( self, - *, - client: Union[AuthenticatedClient, Client], body: PostTasksBody, ) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: """Метод для создания нового напоминания. @@ -123,7 +117,6 @@ async def post_tasks( return ( await self.asyncio_detailed_post_tasks( - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py index b39cd3f..4c89a88 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py @@ -1,10 +1,9 @@ from http import HTTPStatus -from typing import Any, Optional, Union +from typing import Any, Optional import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...types import Response @@ -19,32 +18,26 @@ def _get_kwargs_delStatus( return _kwargs -def _parse_response_delStatus( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Any]: +def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: if response.status_code == 204: return None - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_delStatus( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Any]: +def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_delStatus(client=client, response=response), + parsed=self._parse_response_delStatus(response=response), ) async def asyncio_detailed_delStatus( self, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Any]: """удаление своего статуса @@ -60,6 +53,6 @@ async def asyncio_detailed_delStatus( kwargs = self._get_kwargs_delStatus() - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delStatus(client=client, response=response) + return self._build_response_delStatus(response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py index de2cef2..2440e05 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -1,10 +1,9 @@ from http import HTTPStatus -from typing import Any, Optional, Union +from typing import Any, Optional import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_status_response_200 import GetStatusResponse200 from ...types import Response @@ -20,34 +19,28 @@ def _get_kwargs_getStatus( return _kwargs -def _parse_response_getStatus( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[GetStatusResponse200]: +def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: if response.status_code == 200: response_200 = GetStatusResponse200.from_dict(response.json()) return response_200 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getStatus( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[GetStatusResponse200]: +def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getStatus(client=client, response=response), + parsed=self._parse_response_getStatus(response=response), ) async def asyncio_detailed_getStatus( self, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[GetStatusResponse200]: """получение информации о своем статусе @@ -63,15 +56,13 @@ async def asyncio_detailed_getStatus( kwargs = self._get_kwargs_getStatus() - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getStatus(client=client, response=response) + return self._build_response_getStatus(response=response) async def getStatus( self, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[GetStatusResponse200]: """получение информации о своем статусе @@ -85,8 +76,4 @@ async def getStatus( GetStatusResponse200 """ - return ( - await self.asyncio_detailed_getStatus( - client=client, - ) - ).parsed + return (await self.asyncio_detailed_getStatus()).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py index 916b9e5..e085477 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.put_status_response_201 import PutStatusResponse201 from ...models.query_status import QueryStatus @@ -13,7 +12,6 @@ def _get_kwargs_putStatus( self, - *, body: QueryStatus, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -32,9 +30,7 @@ def _get_kwargs_putStatus( return _kwargs -def _parse_response_putStatus( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[BadRequest, PutStatusResponse201]]: +def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: if response.status_code == 201: response_201 = PutStatusResponse201.from_dict(response.json()) @@ -43,27 +39,23 @@ def _parse_response_putStatus( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_putStatus( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[BadRequest, PutStatusResponse201]]: +def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_putStatus(client=client, response=response), + parsed=self._parse_response_putStatus(response=response), ) async def asyncio_detailed_putStatus( self, - *, - client: Union[AuthenticatedClient, Client], body: QueryStatus, ) -> Response[Union[BadRequest, PutStatusResponse201]]: """новый статус @@ -85,15 +77,13 @@ async def asyncio_detailed_putStatus( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_putStatus(client=client, response=response) + return self._build_response_putStatus(response=response) async def putStatus( self, - *, - client: Union[AuthenticatedClient, Client], body: QueryStatus, ) -> Optional[Union[BadRequest, PutStatusResponse201]]: """новый статус @@ -113,7 +103,6 @@ async def putStatus( return ( await self.asyncio_detailed_putStatus( - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py index e95392c..ac9ad1d 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_tag_response_200 import GetTagResponse200 from ...models.get_tag_response_404 import GetTagResponse404 from ...types import Response @@ -22,9 +21,7 @@ def _get_kwargs_getTag( return _kwargs -def _parse_response_getTag( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: +def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: if response.status_code == 200: response_200 = GetTagResponse200.from_dict(response.json()) @@ -33,28 +30,24 @@ def _parse_response_getTag( response_404 = GetTagResponse404.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getTag( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[GetTagResponse200, GetTagResponse404]]: +def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getTag(client=client, response=response), + parsed=self._parse_response_getTag(response=response), ) async def asyncio_detailed_getTag( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Union[GetTagResponse200, GetTagResponse404]]: """Информация о теге @@ -75,16 +68,14 @@ async def asyncio_detailed_getTag( id=id, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTag(client=client, response=response) + return self._build_response_getTag(response=response) async def getTag( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: """Информация о теге @@ -104,6 +95,5 @@ async def getTag( return ( await self.asyncio_detailed_getTag( id=id, - client=client, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py index 8785365..c3909bb 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.get_tags_response_200 import GetTagsResponse200 from ...models.get_tags_response_400 import GetTagsResponse400 from ...types import UNSET, Response, Unset @@ -12,7 +11,6 @@ def _get_kwargs_getTags( self, - *, per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, ) -> dict[str, Any]: @@ -33,9 +31,7 @@ def _get_kwargs_getTags( return _kwargs -def _parse_response_getTags( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: +def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: if response.status_code == 200: response_200 = GetTagsResponse200.from_dict(response.json()) @@ -44,27 +40,23 @@ def _parse_response_getTags( response_400 = GetTagsResponse400.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_getTags( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: +def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getTags(client=client, response=response), + parsed=self._parse_response_getTags(response=response), ) async def asyncio_detailed_getTags( self, - *, - client: Union[AuthenticatedClient, Client], per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, ) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: @@ -89,15 +81,13 @@ async def asyncio_detailed_getTags( page=page, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(client=client, response=response) + return self._build_response_getTags(response=response) async def getTags( self, - *, - client: Union[AuthenticatedClient, Client], per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, ) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: @@ -119,7 +109,6 @@ async def getTags( return ( await self.asyncio_detailed_getTags( - client=client, per=per, page=page, ) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py index 9a32aa2..eb690ae 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.bad_request import BadRequest from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 from ...types import UNSET, Response, Unset @@ -13,7 +12,6 @@ def _get_kwargs_getTagsEmployees( self, id: int, - *, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, ) -> dict[str, Any]: @@ -35,7 +33,7 @@ def _get_kwargs_getTagsEmployees( def _parse_response_getTagsEmployees( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: if response.status_code == 200: response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) @@ -45,28 +43,26 @@ def _parse_response_getTagsEmployees( response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None def _build_response_getTagsEmployees( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response + self, response: httpx.Response ) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_getTagsEmployees(client=client, response=response), + parsed=self._parse_response_getTagsEmployees(response=response), ) async def asyncio_detailed_getTagsEmployees( self, id: int, - *, - client: Union[AuthenticatedClient, Client], per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, ) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: @@ -93,16 +89,14 @@ async def asyncio_detailed_getTagsEmployees( page=page, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(client=client, response=response) + return self._build_response_getTagsEmployees(response=response) async def getTagsEmployees( self, id: int, - *, - client: Union[AuthenticatedClient, Client], per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, ) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: @@ -126,7 +120,6 @@ async def getTagsEmployees( return ( await self.asyncio_detailed_getTagsEmployees( id=id, - client=client, per=per, page=page, ) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py index 53d8441..ea2661f 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.errors_code import ErrorsCode from ...types import Response @@ -21,9 +20,7 @@ def _get_kwargs_delete_chats_id_leave( return _kwargs -def _parse_response_delete_chats_id_leave( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, list["ErrorsCode"]]]: +def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: if response.status_code == 200: response_200 = cast(Any, None) return response_200 @@ -45,28 +42,24 @@ def _parse_response_delete_chats_id_leave( response_404.append(response_404_item) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_delete_chats_id_leave( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, list["ErrorsCode"]]]: +def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_delete_chats_id_leave(client=client, response=response), + parsed=self._parse_response_delete_chats_id_leave(response=response), ) async def asyncio_detailed_delete_chats_id_leave( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Response[Union[Any, list["ErrorsCode"]]]: """Выход из беседы или канала @@ -87,16 +80,14 @@ async def asyncio_detailed_delete_chats_id_leave( id=id, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(client=client, response=response) + return self._build_response_delete_chats_id_leave(response=response) async def delete_chats_id_leave( self, id: int, - *, - client: Union[AuthenticatedClient, Client], ) -> Optional[Union[Any, list["ErrorsCode"]]]: """Выход из беседы или канала @@ -116,6 +107,5 @@ async def delete_chats_id_leave( return ( await self.asyncio_detailed_delete_chats_id_leave( id=id, - client=client, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py index 807d352..81b5bd6 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.errors_code import ErrorsCode from ...models.post_members_to_chats_body import PostMembersToChatsBody from ...types import Response @@ -13,7 +12,6 @@ def _get_kwargs_postMembersToChats( self, id: int, - *, body: PostMembersToChatsBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -32,9 +30,7 @@ def _get_kwargs_postMembersToChats( return _kwargs -def _parse_response_postMembersToChats( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, list["ErrorsCode"]]]: +def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: if response.status_code == 201: response_201 = cast(Any, None) return response_201 @@ -47,28 +43,24 @@ def _parse_response_postMembersToChats( response_400.append(response_400_item) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_postMembersToChats( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, list["ErrorsCode"]]]: +def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_postMembersToChats(client=client, response=response), + parsed=self._parse_response_postMembersToChats(response=response), ) async def asyncio_detailed_postMembersToChats( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: PostMembersToChatsBody, ) -> Response[Union[Any, list["ErrorsCode"]]]: """добавление пользователей в состав участников @@ -92,16 +84,14 @@ async def asyncio_detailed_postMembersToChats( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(client=client, response=response) + return self._build_response_postMembersToChats(response=response) async def postMembersToChats( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: PostMembersToChatsBody, ) -> Optional[Union[Any, list["ErrorsCode"]]]: """добавление пользователей в состав участников @@ -123,7 +113,6 @@ async def postMembersToChats( return ( await self.asyncio_detailed_postMembersToChats( id=id, - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py index ef3e5cf..f6c445c 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -4,7 +4,6 @@ import httpx from ... import errors -from ...client import AuthenticatedClient, Client from ...models.errors_code import ErrorsCode from ...models.post_tags_to_chats_body import PostTagsToChatsBody from ...types import Response @@ -13,7 +12,6 @@ def _get_kwargs_postTagsToChats( self, id: int, - *, body: PostTagsToChatsBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -32,9 +30,7 @@ def _get_kwargs_postTagsToChats( return _kwargs -def _parse_response_postTagsToChats( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, list["ErrorsCode"]]]: +def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: if response.status_code == 201: response_201 = cast(Any, None) return response_201 @@ -47,28 +43,24 @@ def _parse_response_postTagsToChats( response_400.append(response_400_item) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_postTagsToChats( - self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, list["ErrorsCode"]]]: +def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_postTagsToChats(client=client, response=response), + parsed=self._parse_response_postTagsToChats(response=response), ) async def asyncio_detailed_postTagsToChats( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: PostTagsToChatsBody, ) -> Response[Union[Any, list["ErrorsCode"]]]: """добавление тегов в состав участников беседы или канала @@ -92,16 +84,14 @@ async def asyncio_detailed_postTagsToChats( body=body, ) - response = await client.get_async_httpx_client().request(**kwargs) + response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(client=client, response=response) + return self._build_response_postTagsToChats(response=response) async def postTagsToChats( self, id: int, - *, - client: Union[AuthenticatedClient, Client], body: PostTagsToChatsBody, ) -> Optional[Union[Any, list["ErrorsCode"]]]: """добавление тегов в состав участников беседы или канала @@ -123,7 +113,6 @@ async def postTagsToChats( return ( await self.asyncio_detailed_postTagsToChats( id=id, - client=client, body=body, ) ).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py index 43cd58e..4b1b8ee 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -1,64 +1,62 @@ +from .models.get_chats_response_422 import GetChatsResponse422 +from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from http import HTTPStatus +from .models.post_message_reactions_body import PostMessageReactionsBody +from .models.create_chat_response_422 import CreateChatResponse422 from .models.post_tasks_body import PostTasksBody -from .models.post_tasks_response_201 import PostTasksResponse201 -from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from .models.get_chats_availability import GetChatsAvailability -from .models.get_message_reactions_body import GetMessageReactionsBody +from .models.create_message_response_201 import CreateMessageResponse201 +from .models.get_tags_response_200 import GetTagsResponse200 +from .models.get_tags_response_400 import GetTagsResponse400 +from .models.create_chat_body import CreateChatBody +from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .models.get_employees_response_200 import GetEmployeesResponse200 from .models.get_tag_response_200 import GetTagResponse200 -from .models.not_found import NotFound -from .models.create_message_body import CreateMessageBody +from .models.get_chats_sortid import GetChatsSortid +from .types import UNSET +from .models.get_status_response_200 import GetStatusResponse200 +from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .models.put_status_response_201 import PutStatusResponse201 +from .models.errors_code import ErrorsCode +from .models.direct_response import DirectResponse from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from .models.get_tags_response_200 import GetTagsResponse200 +from .models.get_list_message_response_200 import GetListMessageResponse200 from .models.post_members_to_chats_body import PostMembersToChatsBody -from .types import Response +from .models.file_response import FileResponse +from .models.get_employee_response_200 import GetEmployeeResponse200 +from .models.create_thread_response_200 import CreateThreadResponse200 +from . import errors +from .models.bad_request import BadRequest from .models.create_chat_response_404 import CreateChatResponse404 +from .models.put_messages_id_body import PutMessagesIdBody +from .models.get_tag_response_404 import GetTagResponse404 +from .models.get_message_reactions_body import GetMessageReactionsBody +from .models.create_message_body import CreateMessageBody +from .models.get_chats_availability import GetChatsAvailability +from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .models.get_chats_response_400 import GetChatsResponse400 +from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from .models.post_tags_to_chats_body import PostTagsToChatsBody +from .models.get_chat_response_404 import GetChatResponse404 +from typing import Union from .models.get_chat_response_200 import GetChatResponse200 -from .models.get_tags_response_400 import GetTagsResponse400 -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .models.get_chats_response_422 import GetChatsResponse422 -from .models.get_employees_response_200 import GetEmployeesResponse200 +from .models.create_chat_response_400 import CreateChatResponse400 +from .models.get_chats_response_404 import GetChatsResponse404 from .models.create_chat_response_201 import CreateChatResponse201 from .models.query_status import QueryStatus -from .models.get_chats_response_400 import GetChatsResponse400 -from .models.get_list_message_response_200 import GetListMessageResponse200 +from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from typing import cast from .models.error import Error -from .models.get_status_response_200 import GetStatusResponse200 +from .models.post_tasks_response_201 import PostTasksResponse201 +from .models.not_found import NotFound from .models.post_tasks_response_400 import PostTasksResponse400 -from .models.post_tags_to_chats_body import PostTagsToChatsBody -from .client import AuthenticatedClient -from .client import Client -from .models.create_chat_response_422 import CreateChatResponse422 -from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .models.get_message_response_200 import GetMessageResponse200 from .models.get_chats_response_200 import GetChatsResponse200 -from .models.create_chat_body import CreateChatBody -from typing import Union -from . import errors +from .types import Response from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from .types import UNSET -from .types import Unset -from http import HTTPStatus -from .models.direct_response import DirectResponse -from typing import cast -from .models.create_chat_response_400 import CreateChatResponse400 -from typing import Optional -from .models.file_response import FileResponse -from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 -from .models.post_message_reactions_body import PostMessageReactionsBody -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.bad_request import BadRequest -from .models.get_chats_sortid import GetChatsSortid from typing import Any -from .models.put_status_response_201 import PutStatusResponse201 -from .models.get_chats_response_404 import GetChatsResponse404 -from .models.get_chat_response_404 import GetChatResponse404 -from .models.create_thread_response_200 import CreateThreadResponse200 -from .models.get_message_response_200 import GetMessageResponse200 -from .models.put_messages_id_body import PutMessagesIdBody -from .models.create_message_response_201 import CreateMessageResponse201 -from .models.get_tag_response_404 import GetTagResponse404 -from .models.get_employee_response_200 import GetEmployeeResponse200 -from .models.errors_code import ErrorsCode +from typing import Optional +from .types import Unset import datetime import ssl @@ -331,8 +329,7 @@ async def __aexit__(self, *args: Any, **kwargs: Any) -> None: """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" await self.get_async_httpx_client().__aexit__(*args, **kwargs) - -@define + class Pachca: """Главный класс библиотеки.""" @@ -341,402 +338,184 @@ def __init__(self, base_url, token): - def _get_kwargs_createChat(self, *, body: CreateChatBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} return _kwargs - def _parse_response_createChat(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) - return response_400 + def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + return response_200 if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) + response_404 = NotFound.from_dict(response.json()) return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - return response_422 - if client.raise_on_unexpected_status: + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createChat(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(client=client, response=response)) + def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) - async def asyncio_detailed_createChat(self, *, client: Union[AuthenticatedClient, Client], body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал + async def asyncio_detailed_createThread(self, id: int) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. Args: - body (CreateChatBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] - """ - kwargs = self._get_kwargs_createChat(body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(client=client, response=response) + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + kwargs = self._get_kwargs_createThread(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createThread(response=response) - async def createChat(self, *, client: Union[AuthenticatedClient, Client], body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал + async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. Args: - body (CreateChatBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - return (await self.asyncio_detailed_createChat(client=client, body=body)).parsed + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + return (await self.asyncio_detailed_createThread(id=id)).parsed - def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} + def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['entity_type'] = entity_type + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} return _kwargs - def _parse_response_getChat(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) return response_200 - if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) - return response_404 - if client.raise_on_unexpected_status: + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getChat(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(client=client, response=response)) + def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) - async def asyncio_detailed_getChat(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале + async def asyncio_detailed_getCommonMethods(self, entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. Args: - id (int): + entity_type (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatResponse200, GetChatResponse404]] + Response[Union[BadRequest, GetCommonMethodsResponse200]] """ - kwargs = self._get_kwargs_getChat(id=id) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(client=client, response=response) + kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getCommonMethods(response=response) - async def getChat(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале + async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. Args: - id (int): + entity_type (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetChatResponse200, GetChatResponse404] + Union[BadRequest, GetCommonMethodsResponse200] """ - return (await self.asyncio_detailed_getChat(id=id, client=client)).parsed + return (await self.asyncio_detailed_getCommonMethods(entity_type=entity_type)).parsed - def _get_kwargs_getChats(self, *, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - params['sort[id]'] = json_sortid - params['per'] = per - params['page'] = page - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - params['availability'] = json_availability - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params['last_message_at_after'] = json_last_message_at_after - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params['last_message_at_before'] = json_last_message_at_before - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} + def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} + _body = body.to_multipart() + _kwargs['files'] = _body + _kwargs['headers'] = headers return _kwargs - def _parse_response_getChats(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - return response_422 - if client.raise_on_unexpected_status: + def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getChats(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(client=client, response=response)) + def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) - async def asyncio_detailed_getChats(self, *, client: Union[AuthenticatedClient, Client], sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов + async def asyncio_detailed_getDirectUrl(self, body: DirectResponse) -> Response[Any]: + """Получение URL для загрузки - Получения списка бесед и каналов по заданным параметрам. + Отправляет запрос для получения URL для безопасной загрузки файла. Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): + body (DirectResponse): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + Response[Any] """ - kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(client=client, response=response) + kwargs = self._get_kwargs_getDirectUrl(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getDirectUrl(response=response) - async def getChats(self, *, client: Union[AuthenticatedClient, Client], sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов + def _get_kwargs_getUploads(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} + return _kwargs + + def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) + + async def asyncio_detailed_getUploads(self) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - return (await self.asyncio_detailed_getChats(client=client, sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed - - def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} - return _kwargs - - def _parse_response_createThread(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createThread(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(client=client, response=response)) - - async def asyncio_detailed_createThread(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, CreateThreadResponse200, NotFound]] - """ - kwargs = self._get_kwargs_createThread(id=id) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(client=client, response=response) - - async def createThread(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - return (await self.asyncio_detailed_createThread(id=id, client=client)).parsed - - def _get_kwargs_getCommonMethods(self, *, entity_type: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['entity_type'] = entity_type - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} - return _kwargs - - def _parse_response_getCommonMethods(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getCommonMethods(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(client=client, response=response)) - - async def asyncio_detailed_getCommonMethods(self, *, client: Union[AuthenticatedClient, Client], entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, GetCommonMethodsResponse200]] - """ - kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(client=client, response=response) - - async def getCommonMethods(self, *, client: Union[AuthenticatedClient, Client], entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetCommonMethodsResponse200] - """ - return (await self.asyncio_detailed_getCommonMethods(client=client, entity_type=entity_type)).parsed - - def _get_kwargs_getDirectUrl(self, *, body: DirectResponse) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} - _body = body.to_multipart() - _kwargs['files'] = _body - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_getDirectUrl(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getDirectUrl(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(client=client, response=response)) - - async def asyncio_detailed_getDirectUrl(self, *, client: Union[AuthenticatedClient, Client], body: DirectResponse) -> Response[Any]: - """Получение URL для загрузки - - Отправляет запрос для получения URL для безопасной загрузки файла. - - Args: - body (DirectResponse): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - kwargs = self._get_kwargs_getDirectUrl(body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getDirectUrl(client=client, response=response) - - def _get_kwargs_getUploads(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} - return _kwargs - - def _parse_response_getUploads(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[FileResponse]: - if response.status_code == 200: - response_200 = FileResponse.from_dict(response.json()) - return response_200 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getUploads(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[FileResponse]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(client=client, response=response)) - - async def asyncio_detailed_getUploads(self, *, client: Union[AuthenticatedClient, Client]) -> Response[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. + Возвращает параметры, необходимые для безопасной загрузки файла. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -746,10 +525,10 @@ async def asyncio_detailed_getUploads(self, *, client: Union[AuthenticatedClient Response[FileResponse] """ kwargs = self._get_kwargs_getUploads() - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getUploads(client=client, response=response) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getUploads(response=response) - async def getUploads(self, *, client: Union[AuthenticatedClient, Client]) -> Optional[FileResponse]: + async def getUploads(self) -> Optional[FileResponse]: """Получение подписи и ключа для загрузки файла Возвращает параметры, необходимые для безопасной загрузки файла. @@ -761,127 +540,82 @@ async def getUploads(self, *, client: Union[AuthenticatedClient, Client]) -> Opt Returns: FileResponse """ - return (await self.asyncio_detailed_getUploads(client=client)).parsed + return (await self.asyncio_detailed_getUploads()).parsed - def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} + def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getEmployee(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) + response_200 = PutMessagesIdResponse200.from_dict(response.json()) return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getEmployee(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(client=client, response=response)) + def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) - async def asyncio_detailed_getEmployee(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике + async def asyncio_detailed_put_messages_id(self, id: int, body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + Метод для редактирования сообщения или комментария. Args: id (int): + body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetEmployeeResponse200, NotFound]] + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_getEmployee(id=id) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(client=client, response=response) + kwargs = self._get_kwargs_put_messages_id(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_put_messages_id(response=response) - async def getEmployee(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике + async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + Метод для редактирования сообщения или комментария. Args: id (int): + body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetEmployeeResponse200, NotFound] - """ - return (await self.asyncio_detailed_getEmployee(id=id, client=client)).parsed - - def _get_kwargs_getEmployees(self, *, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params['query'] = query - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} - return _kwargs - - def _parse_response_getEmployees(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[GetEmployeesResponse200]: - if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) - return response_200 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getEmployees(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(client=client, response=response)) - - async def asyncio_detailed_getEmployees(self, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[GetEmployeesResponse200] - """ - kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(client=client, response=response) - - async def getEmployees(self, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetEmployeesResponse200 + Union[PutMessagesIdResponse200, list['ErrorsCode']] """ - return (await self.asyncio_detailed_getEmployees(client=client, per=per, page=page, query=query)).parsed + return (await self.asyncio_detailed_put_messages_id(id=id, body=body)).parsed - def _get_kwargs_createMessage(self, *, body: CreateMessageBody) -> dict[str, Any]: + def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: headers: dict[str, Any] = {} _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} _body = body.to_dict() @@ -890,7 +624,7 @@ def _get_kwargs_createMessage(self, *, body: CreateMessageBody) -> dict[str, Any _kwargs['headers'] = headers return _kwargs - def _parse_response_createMessage(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: if response.status_code == 201: response_201 = CreateMessageResponse201.from_dict(response.json()) return response_201 @@ -904,15 +638,15 @@ def _parse_response_createMessage(self, *, client: Union[AuthenticatedClient, Cl if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createMessage(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(client=client, response=response)) + def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) - async def asyncio_detailed_createMessage(self, *, client: Union[AuthenticatedClient, Client], body: CreateMessageBody) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + async def asyncio_detailed_createMessage(self, body: CreateMessageBody) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: """создание нового сообщения Метод для отправки сообщения в беседу или канал, @@ -940,10 +674,10 @@ async def asyncio_detailed_createMessage(self, *, client: Union[AuthenticatedCli Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] """ kwargs = self._get_kwargs_createMessage(body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_createMessage(client=client, response=response) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createMessage(response=response) - async def createMessage(self, *, client: Union[AuthenticatedClient, Client], body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: """создание нового сообщения Метод для отправки сообщения в беседу или канал, @@ -968,11 +702,70 @@ async def createMessage(self, *, client: Union[AuthenticatedClient, Client], bod httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + return (await self.asyncio_detailed_createMessage(body=body)).parsed + + def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} + return _kwargs + + def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) + + async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetMessageResponse200, NotFound]] + """ + kwargs = self._get_kwargs_getMessage(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getMessage(response=response) + + async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_createMessage(client=client, body=body)).parsed + return (await self.asyncio_detailed_getMessage(id=id)).parsed - def _get_kwargs_getListMessage(self, *, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} params['chat_id'] = chat_id params['per'] = per @@ -981,7 +774,7 @@ def _get_kwargs_getListMessage(self, *, chat_id: int, per: Union[Unset, int]=25, _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} return _kwargs - def _parse_response_getListMessage(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: if response.status_code == 200: response_200 = GetListMessageResponse200.from_dict(response.json()) return response_200 @@ -991,15 +784,15 @@ def _parse_response_getListMessage(self, *, client: Union[AuthenticatedClient, C if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getListMessage(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(client=client, response=response)) + def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) - async def asyncio_detailed_getListMessage(self, *, client: Union[AuthenticatedClient, Client], chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + async def asyncio_detailed_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: """получение списка сообщений чата Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. @@ -1022,10 +815,10 @@ async def asyncio_detailed_getListMessage(self, *, client: Union[AuthenticatedCl Response[Union[BadRequest, GetListMessageResponse200, NotFound]] """ kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getListMessage(client=client, response=response) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getListMessage(response=response) - async def getListMessage(self, *, client: Union[AuthenticatedClient, Client], chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: """получение списка сообщений чата Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. @@ -1047,79 +840,81 @@ async def getListMessage(self, *, client: Union[AuthenticatedClient, Client], ch Returns: Union[BadRequest, GetListMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_getListMessage(client=client, chat_id=chat_id, per=per, page=page)).parsed + return (await self.asyncio_detailed_getListMessage(chat_id=chat_id, per=per, page=page)).parsed - def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} + def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getMessage(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if client.raise_on_unexpected_status: + def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getMessage(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(client=client, response=response)) + def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) - async def asyncio_detailed_getMessage(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. + async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + Метод для добавления тегов в состав участников беседы или канала. Args: - id (int): + id (int): Example: 533. + body (PostTagsToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetMessageResponse200, NotFound]] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_getMessage(id=id) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(client=client, response=response) + kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postTagsToChats(response=response) - async def getMessage(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. + async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + Метод для добавления тегов в состав участников беседы или канала. Args: - id (int): + id (int): Example: 533. + body (PostTagsToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetMessageResponse200, NotFound] + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_getMessage(id=id, client=client)).parsed + return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed - def _get_kwargs_put_messages_id(self, id: int, *, body: PutMessagesIdBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} return _kwargs - def _parse_response_put_messages_id(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: if response.status_code == 200: - response_200 = PutMessagesIdResponse200.from_dict(response.json()) + response_200 = cast(Any, None) return response_200 if response.status_code == 400: response_400 = [] @@ -1135,342 +930,456 @@ def _parse_response_put_messages_id(self, *, client: Union[AuthenticatedClient, response_404_item = ErrorsCode.from_dict(response_404_item_data) response_404.append(response_404_item) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_put_messages_id(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(client=client, response=response)) + def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) - async def asyncio_detailed_put_messages_id(self, id: int, *, client: Union[AuthenticatedClient, Client], body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения + async def asyncio_detailed_delete_chats_id_leave(self, id: int) -> Response[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала - Метод для редактирования сообщения или комментария. + Метод для самостоятельного выхода из беседы или канала. Args: id (int): - body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_put_messages_id(id=id, body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(client=client, response=response) + kwargs = self._get_kwargs_delete_chats_id_leave(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_delete_chats_id_leave(response=response) - async def put_messages_id(self, id: int, *, client: Union[AuthenticatedClient, Client], body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения + async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала - Метод для редактирования сообщения или комментария. + Метод для самостоятельного выхода из беседы или канала. Args: id (int): - body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[PutMessagesIdResponse200, list['ErrorsCode']] + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_put_messages_id(id=id, client=client, body=body)).parsed + return (await self.asyncio_detailed_delete_chats_id_leave(id=id)).parsed - def _get_kwargs_deleteMessageReactions(self, id: str, *, code: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['code'] = code - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} + def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_deleteMessageReactions(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 + def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) + + async def asyncio_detailed_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postMembersToChats(response=response) + + async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + return (await self.asyncio_detailed_postMembersToChats(id=id, body=body)).parsed + + def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} + return _kwargs + + def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + return response_200 if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + response_404 = GetChatResponse404.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_deleteMessageReactions(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(client=client, response=response)) + def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) - async def asyncio_detailed_deleteMessageReactions(self, id: str, *, client: Union[AuthenticatedClient, Client], code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции + async def asyncio_detailed_getChat(self, id: int) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. Args: - id (str): - code (str): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + Response[Union[GetChatResponse200, GetChatResponse404]] """ - kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(client=client, response=response) + kwargs = self._get_kwargs_getChat(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChat(response=response) - async def deleteMessageReactions(self, id: str, *, client: Union[AuthenticatedClient, Client], code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции + async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. Args: - id (str): - code (str): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + Union[GetChatResponse200, GetChatResponse404] """ - return (await self.asyncio_detailed_deleteMessageReactions(id=id, client=client, code=code)).parsed + return (await self.asyncio_detailed_getChat(id=id)).parsed - def _get_kwargs_getMessageReactions(self, id: int, *, body: GetMessageReactionsBody) -> dict[str, Any]: + def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} _body = body.to_dict() _kwargs['json'] = _body headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_getMessageReactions(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) - return response_200 + def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + return response_400 if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) + response_404 = CreateChatResponse404.from_dict(response.json()) return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + return response_422 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) + + async def asyncio_detailed_createChat(self, body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + kwargs = self._get_kwargs_createChat(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createChat(response=response) + + async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + return (await self.asyncio_detailed_createChat(body=body)).parsed + + def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + params['sort[id]'] = json_sortid + params['per'] = per + params['page'] = page + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + params['availability'] = json_availability + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params['last_message_at_after'] = json_last_message_at_after + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params['last_message_at_before'] = json_last_message_at_before + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} + return _kwargs + + def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + return response_200 if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) + response_400 = GetChatsResponse400.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + return response_422 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getMessageReactions(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(client=client, response=response)) + def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) - async def asyncio_detailed_getMessageReactions(self, id: int, *, client: Union[AuthenticatedClient, Client], body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. + async def asyncio_detailed_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. + Получения списка бесед и каналов по заданным параметрам. Args: - id (int): - body (GetMessageReactionsBody): + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] """ - kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(client=client, response=response) + kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChats(response=response) - async def getMessageReactions(self, id: int, *, client: Union[AuthenticatedClient, Client], body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. + async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. + Получения списка бесед и каналов по заданным параметрам. Args: - id (int): - body (GetMessageReactionsBody): + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] """ - return (await self.asyncio_detailed_getMessageReactions(id=id, client=client, body=body)).parsed + return (await self.asyncio_detailed_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed - def _get_kwargs_postMessageReactions(self, id: str, *, body: PostMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getStatus(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} return _kwargs - def _parse_response_postMessageReactions(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - return response_404 - if client.raise_on_unexpected_status: + def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postMessageReactions(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(client=client, response=response)) + def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) - async def asyncio_detailed_postMessageReactions(self, id: str, *, client: Union[AuthenticatedClient, Client], body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. + async def asyncio_detailed_getStatus(self) -> Response[GetStatusResponse200]: + """получение информации о своем статусе - Args: - id (str): - body (PostMessageReactionsBody): + Параметры запроса отсутствуют Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + Response[GetStatusResponse200] """ - kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(client=client, response=response) + kwargs = self._get_kwargs_getStatus() + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getStatus(response=response) - async def postMessageReactions(self, id: str, *, client: Union[AuthenticatedClient, Client], body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. + async def getStatus(self) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе - Args: - id (str): - body (PostMessageReactionsBody): + Параметры запроса отсутствуют Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + GetStatusResponse200 """ - return (await self.asyncio_detailed_postMessageReactions(id=id, client=client, body=body)).parsed + return (await self.asyncio_detailed_getStatus()).parsed - def _get_kwargs_post_tasks(self, *, body: PostTasksBody) -> dict[str, Any]: + def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} + _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} _body = body.to_dict() _kwargs['json'] = _body headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_post_tasks(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: if response.status_code == 201: - response_201 = PostTasksResponse201.from_dict(response.json()) + response_201 = PutStatusResponse201.from_dict(response.json()) return response_201 if response.status_code == 400: - response_400 = PostTasksResponse400.from_dict(response.json()) + response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_post_tasks(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(client=client, response=response)) + def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) - async def asyncio_detailed_post_tasks(self, *, client: Union[AuthenticatedClient, Client], body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. + async def asyncio_detailed_putStatus(self, body: QueryStatus) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + Создание нового статуса. Args: - body (PostTasksBody): + body (QueryStatus): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PostTasksResponse201, PostTasksResponse400]] + Response[Union[BadRequest, PutStatusResponse201]] """ - kwargs = self._get_kwargs_post_tasks(body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(client=client, response=response) + kwargs = self._get_kwargs_putStatus(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_putStatus(response=response) - async def post_tasks(self, *, client: Union[AuthenticatedClient, Client], body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. + async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + Создание нового статуса. Args: - body (PostTasksBody): + body (QueryStatus): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[PostTasksResponse201, PostTasksResponse400] + Union[BadRequest, PutStatusResponse201] """ - return (await self.asyncio_detailed_post_tasks(client=client, body=body)).parsed + return (await self.asyncio_detailed_putStatus(body=body)).parsed def _get_kwargs_delStatus(self) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} return _kwargs - def _parse_response_delStatus(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: if response.status_code == 204: return None - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_delStatus(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(client=client, response=response)) + def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) - async def asyncio_detailed_delStatus(self, *, client: Union[AuthenticatedClient, Client]) -> Response[Any]: + async def asyncio_detailed_delStatus(self) -> Response[Any]: """удаление своего статуса Параметры запроса отсутствуют @@ -1483,490 +1392,578 @@ async def asyncio_detailed_delStatus(self, *, client: Union[AuthenticatedClient, Response[Any] """ kwargs = self._get_kwargs_delStatus() - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_delStatus(client=client, response=response) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_delStatus(response=response) - def _get_kwargs_getStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} + def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} return _kwargs - def _parse_response_getStatus(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[GetStatusResponse200]: + def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: if response.status_code == 200: - response_200 = GetStatusResponse200.from_dict(response.json()) + response_200 = GetTagsResponse200.from_dict(response.json()) return response_200 - if client.raise_on_unexpected_status: + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getStatus(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[GetStatusResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(client=client, response=response)) + def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - async def asyncio_detailed_getStatus(self, *, client: Union[AuthenticatedClient, Client]) -> Response[GetStatusResponse200]: - """получение информации о своем статусе + async def asyncio_detailed_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetTagsResponse200, GetTagsResponse400]] + """ + kwargs = self._get_kwargs_getTags(per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTags(response=response) + + async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + return (await self.asyncio_detailed_getTags(per=per, page=page)).parsed + + def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} + return _kwargs + + def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) + + async def asyncio_detailed_getTag(self, id: int) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге Параметры запроса отсутствуют + Args: + id (int): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[GetStatusResponse200] + Response[Union[GetTagResponse200, GetTagResponse404]] """ - kwargs = self._get_kwargs_getStatus() - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getStatus(client=client, response=response) + kwargs = self._get_kwargs_getTag(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTag(response=response) - async def getStatus(self, *, client: Union[AuthenticatedClient, Client]) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе + async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге Параметры запроса отсутствуют + Args: + id (int): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - GetStatusResponse200 + Union[GetTagResponse200, GetTagResponse404] """ - return (await self.asyncio_detailed_getStatus(client=client)).parsed + return (await self.asyncio_detailed_getTag(id=id)).parsed - def _get_kwargs_putStatus(self, *, body: QueryStatus) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} return _kwargs - def _parse_response_putStatus(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: - if response.status_code == 201: - response_201 = PutStatusResponse201.from_dict(response.json()) - return response_201 + def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + return response_200 if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_putStatus(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(client=client, response=response)) + def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - async def asyncio_detailed_putStatus(self, *, client: Union[AuthenticatedClient, Client], body: QueryStatus) -> Response[Union[BadRequest, PutStatusResponse201]]: - """новый статус + async def asyncio_detailed_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега - Создание нового статуса. + Метод для получения актуального списка сотрудников тега. Args: - body (QueryStatus): + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, PutStatusResponse201]] + Response[Union[BadRequest, GetTagsEmployeesResponse200]] """ - kwargs = self._get_kwargs_putStatus(body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_putStatus(client=client, response=response) + kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTagsEmployees(response=response) - async def putStatus(self, *, client: Union[AuthenticatedClient, Client], body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус + async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега - Создание нового статуса. + Метод для получения актуального списка сотрудников тега. Args: - body (QueryStatus): + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, PutStatusResponse201] + Union[BadRequest, GetTagsEmployeesResponse200] """ - return (await self.asyncio_detailed_putStatus(client=client, body=body)).parsed + return (await self.asyncio_detailed_getTagsEmployees(id=id, per=per, page=page)).parsed - def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} + def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getTag(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - if response.status_code == 200: - response_200 = GetTagResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = GetTagResponse404.from_dict(response.json()) - return response_404 - if client.raise_on_unexpected_status: + def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = PostTasksResponse400.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getTag(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(client=client, response=response)) + def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) - async def asyncio_detailed_getTag(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге + async def asyncio_detailed_post_tasks(self, body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. - Параметры запроса отсутствуют + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. Args: - id (int): + body (PostTasksBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetTagResponse200, GetTagResponse404]] + Response[Union[PostTasksResponse201, PostTasksResponse400]] """ - kwargs = self._get_kwargs_getTag(id=id) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTag(client=client, response=response) + kwargs = self._get_kwargs_post_tasks(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_post_tasks(response=response) - async def getTag(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге + async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. - Параметры запроса отсутствуют + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. Args: - id (int): + body (PostTasksBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetTagResponse200, GetTagResponse404] + Union[PostTasksResponse201, PostTasksResponse400] """ - return (await self.asyncio_detailed_getTag(id=id, client=client)).parsed + return (await self.asyncio_detailed_post_tasks(body=body)).parsed - def _get_kwargs_getTags(self, *, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} + def _get_kwargs_postMessageReactions(self, id: str, body: PostMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getTags(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - return response_200 + def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getTags(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(client=client, response=response)) + def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - async def asyncio_detailed_getTags(self, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников + async def asyncio_detailed_postMessageReactions(self, id: str, body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции - Метод для получения актуального списка тегов сотрудников. + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. + id (str): + body (PostMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetTagsResponse200, GetTagsResponse400]] + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] """ - kwargs = self._get_kwargs_getTags(per=per, page=page) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(client=client, response=response) + kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postMessageReactions(response=response) - async def getTags(self, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников + async def postMessageReactions(self, id: str, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции - Метод для получения актуального списка тегов сотрудников. + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. + id (str): + body (PostMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetTagsResponse200, GetTagsResponse400] + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] """ - return (await self.asyncio_detailed_getTags(client=client, per=per, page=page)).parsed + return (await self.asyncio_detailed_postMessageReactions(id=id, body=body)).parsed - def _get_kwargs_getTagsEmployees(self, id: int, *, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} + def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getTagsEmployees(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getTagsEmployees(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(client=client, response=response)) + def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) - async def asyncio_detailed_getTagsEmployees(self, id: int, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега + async def asyncio_detailed_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. - Метод для получения актуального списка сотрудников тега. + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. Args: id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. + body (GetMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetTagsEmployeesResponse200]] + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] """ - kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(client=client, response=response) + kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getMessageReactions(response=response) - async def getTagsEmployees(self, id: int, *, client: Union[AuthenticatedClient, Client], per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега + async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. - Метод для получения актуального списка сотрудников тега. + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. Args: id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. + body (GetMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetTagsEmployeesResponse200] + Union[BadRequest, GetMessageReactionsResponse200, NotFound] """ - return (await self.asyncio_detailed_getTagsEmployees(id=id, client=client, per=per, page=page)).parsed + return (await self.asyncio_detailed_getMessageReactions(id=id, body=body)).parsed - def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} + def _get_kwargs_deleteMessageReactions(self, id: str, code: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['code'] = code + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} return _kwargs - def _parse_response_delete_chats_id_leave(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = cast(Any, None) - return response_200 + def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) return response_400 if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) return response_404 - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_delete_chats_id_leave(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(client=client, response=response)) + def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) - async def asyncio_detailed_delete_chats_id_leave(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Response[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала + async def asyncio_detailed_deleteMessageReactions(self, id: str, code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции - Метод для самостоятельного выхода из беседы или канала. + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. Args: - id (int): + id (str): + code (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] """ - kwargs = self._get_kwargs_delete_chats_id_leave(id=id) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(client=client, response=response) + kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_deleteMessageReactions(response=response) - async def delete_chats_id_leave(self, id: int, *, client: Union[AuthenticatedClient, Client]) -> Optional[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала + async def deleteMessageReactions(self, id: str, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции - Метод для самостоятельного выхода из беседы или канала. + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. Args: - id (int): + id (str): + code (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] """ - return (await self.asyncio_detailed_delete_chats_id_leave(id=id, client=client)).parsed + return (await self.asyncio_detailed_deleteMessageReactions(id=id, code=code)).parsed - def _get_kwargs_postMembersToChats(self, id: int, *, body: PostMembersToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params['query'] = query + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} return _kwargs - def _parse_response_postMembersToChats(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if client.raise_on_unexpected_status: + def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postMembersToChats(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(client=client, response=response)) + def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) - async def asyncio_detailed_postMembersToChats(self, id: int, *, client: Union[AuthenticatedClient, Client], body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников + async def asyncio_detailed_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании - Метод для добавления пользователей в состав участников беседы или канала. + Fetch a paginated list of employees with optional filtering by query. Args: - id (int): Example: 533. - body (PostMembersToChatsBody): + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[GetEmployeesResponse200] """ - kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(client=client, response=response) + kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployees(response=response) - async def postMembersToChats(self, id: int, *, client: Union[AuthenticatedClient, Client], body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников + async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании - Метод для добавления пользователей в состав участников беседы или канала. + Fetch a paginated list of employees with optional filtering by query. Args: - id (int): Example: 533. - body (PostMembersToChatsBody): + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + GetEmployeesResponse200 """ - return (await self.asyncio_detailed_postMembersToChats(id=id, client=client, body=body)).parsed + return (await self.asyncio_detailed_getEmployees(per=per, page=page, query=query)).parsed - def _get_kwargs_postTagsToChats(self, id: int, *, body: PostTagsToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} return _kwargs - def _parse_response_postTagsToChats(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if client.raise_on_unexpected_status: + def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postTagsToChats(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(client=client, response=response)) + def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) - async def asyncio_detailed_postTagsToChats(self, id: int, *, client: Union[AuthenticatedClient, Client], body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала + async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике - Метод для добавления тегов в состав участников беседы или канала. + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. Args: - id (int): Example: 533. - body (PostTagsToChatsBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[GetEmployeeResponse200, NotFound]] """ - kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) - response = await client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(client=client, response=response) + kwargs = self._get_kwargs_getEmployee(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployee(response=response) - async def postTagsToChats(self, id: int, *, client: Union[AuthenticatedClient, Client], body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала + async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике - Метод для добавления тегов в состав участников беседы или канала. + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. Args: - id (int): Example: 533. - body (PostTagsToChatsBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[GetEmployeeResponse200, NotFound] """ - return (await self.asyncio_detailed_postTagsToChats(id=id, client=client, body=body)).parsed + return (await self.asyncio_detailed_getEmployee(id=id)).parsed \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pyproject.toml b/pachca-api-open-api-3-0-client/pyproject.toml index 29f8de8..da5dcfa 100644 --- a/pachca-api-open-api-3-0-client/pyproject.toml +++ b/pachca-api-open-api-3-0-client/pyproject.toml @@ -12,8 +12,8 @@ include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] [tool.poetry.dependencies] python = "^3.9" -httpx = ">=0.20.0,<0.28.0" -attrs = ">=21.3.0" +httpx = ">=0.20.0,<0.29.0" +attrs = ">=22.2.0" python-dateutil = "^2.8.0" [build-system] diff --git a/pachca.py b/pachca.py index 4f882fe..49e95b9 100644 --- a/pachca.py +++ b/pachca.py @@ -1,12 +1,12 @@ import asyncio -from pachca_api_open_api_3_0_client import AuthenticatedClient from pachca_api_open_api_3_0_client.api.chats_and_channels.create_chat import ( - asyncio as as2, + createChat, ) from pachca_api_open_api_3_0_client.api.employees.get_employees import ( - asyncio as as1, + getEmployees, ) +from pachca_api_open_api_3_0_client.client import AuthenticatedClient, Pachca from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, ) @@ -21,13 +21,20 @@ chat_body = CreateChatBody(chat=query_chat) +pachca = Pachca( + base_url='https://api.pachca.com/api/shared/v1', + token='35KekGygDNiFwtPpqUe44CaEZ_EVL17ycYRJrMnvHOs', +) + + async def main(): - task1 = asyncio.create_task(as1(client=client)) - task2 = asyncio.create_task(as2(client=client, body=chat_body)) + task2 = asyncio.create_task(pachca.createChat(body=chat_body)) + task3 = asyncio.create_task(pachca.getEmployees()) - print(await task1) print('*' * 30) print(await task2) + print('*' * 30) + print(await task3) if __name__ == '__main__': diff --git a/script.py b/script.py index 1f529cd..5a140e3 100644 --- a/script.py +++ b/script.py @@ -4,15 +4,16 @@ from jinja2 import Environment, FileSystemLoader -def extract_functions_and_imports_from_file(file_path): +def extract_functions_and_imports_from_file(file_path) -> None: with open(file_path, "r", encoding="utf-8") as file: tree = ast.parse(file.read()) functions = [] imports = [] - + for node in ast.walk(tree): - if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, ast.FunctionDef): + if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, + ast.FunctionDef): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): # Убираем пробел после 'from' и обрабатываем импорты diff --git a/templates/client.py.jinja b/templates/client.py.jinja index f0915ce..8c11934 100644 --- a/templates/client.py.jinja +++ b/templates/client.py.jinja @@ -255,8 +255,7 @@ class AuthenticatedClient: """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" await self.get_async_httpx_client().__aexit__(*args, **kwargs) - -@define + class Pachca: """Главный класс библиотеки.""" diff --git a/templates/endpoint_macros.py.jinja b/templates/endpoint_macros.py.jinja new file mode 100644 index 0000000..8abe5ad --- /dev/null +++ b/templates/endpoint_macros.py.jinja @@ -0,0 +1,174 @@ +{% from "property_templates/helpers.jinja" import guarded_statement %} +{% from "helpers.jinja" import safe_docstring %} + +{% macro header_params(endpoint) %} +{% if endpoint.header_parameters or endpoint.bodies | length > 0 %} +headers: dict[str, Any] = {} +{% if endpoint.header_parameters %} + {% for parameter in endpoint.header_parameters %} + {% import "property_templates/" + parameter.template as param_template %} + {% if param_template.transform_header %} + {% set expression = param_template.transform_header(parameter.python_name) %} + {% else %} + {% set expression = parameter.python_name %} + {% endif %} + {% set statement = 'headers["' + parameter.name + '"]' + " = " + expression %} +{{ guarded_statement(parameter, parameter.python_name, statement) }} + {% endfor %} +{% endif %} +{% endif %} +{% endmacro %} + +{% macro cookie_params(endpoint) %} +{% if endpoint.cookie_parameters %} +cookies = {} + {% for parameter in endpoint.cookie_parameters %} + {% if parameter.required %} +cookies["{{ parameter.name}}"] = {{ parameter.python_name }} + {% else %} +if {{ parameter.python_name }} is not UNSET: + cookies["{{ parameter.name}}"] = {{ parameter.python_name }} + {% endif %} + + {% endfor %} +{% endif %} +{% endmacro %} + + +{% macro query_params(endpoint) %} +{% if endpoint.query_parameters %} +params: dict[str, Any] = {} + +{% for property in endpoint.query_parameters %} + {% set destination = property.python_name %} + {% import "property_templates/" + property.template as prop_template %} + {% if prop_template.transform %} + {% set destination = "json_" + property.python_name %} +{{ prop_template.transform(property, property.python_name, destination) }} + {% endif %} + {%- if not property.json_is_dict %} +params["{{ property.name }}"] = {{ destination }} + {% else %} +{{ guarded_statement(property, destination, "params.update(" + destination + ")") }} + {% endif %} + +{% endfor %} + +params = {k: v for k, v in params.items() if v is not UNSET and v is not None} +{% endif %} +{% endmacro %} + +{% macro body_to_kwarg(body, destination) %} +{% if body.body_type == "data" %} +{{ destination }} = body.to_dict() +{% elif body.body_type == "files"%} +{{ multipart_body(body, destination) }} +{% elif body.body_type == "json" %} +{{ json_body(body, destination) }} +{% elif body.body_type == "content" %} +{{ destination }} = body.payload +{% endif %} +{% endmacro %} + +{% macro json_body(body, destination) %} +{% set property = body.prop %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform %} +{{ prop_template.transform(property, property.python_name, destination) }} +{% else %} +{{ destination }} = {{ property.python_name }} +{% endif %} +{% endmacro %} + +{% macro multipart_body(body, destination) %} +{% set property = body.prop %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform_multipart_body %} +{{ prop_template.transform_multipart_body(property, property.python_name, destination) }} +{% endif %} +{% endmacro %} + +{# The all the kwargs passed into an endpoint (and variants thereof)) #} +{% macro arguments(endpoint, include_client=True) %} +{# path parameters #} +{% for parameter in endpoint.path_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{% if include_client or ((endpoint.list_all_parameters() | length) > (endpoint.path_parameters | length)) %} +{% endif %} +{# Any allowed bodies #} +{% if endpoint.bodies | length == 1 %} +body: {{ endpoint.bodies[0].prop.get_type_string() }}, +{% elif endpoint.bodies | length > 1 %} +body: Union[ + {% for body in endpoint.bodies %} + {{ body.prop.get_type_string() }}, + {% endfor %} +], +{% endif %} +{# query parameters #} +{% for parameter in endpoint.query_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{% for parameter in endpoint.header_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{# cookie parameters #} +{% for parameter in endpoint.cookie_parameters %} +{{ parameter.to_string() }}, +{% endfor %} +{% endmacro %} + +{# Just lists all kwargs to endpoints as name=name for passing to other functions #} +{% macro kwargs(endpoint, include_client=True) %} +{% for parameter in endpoint.path_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% if endpoint.bodies | length > 0 %} +body=body, +{% endif %} +{% for parameter in endpoint.query_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% for parameter in endpoint.header_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% for parameter in endpoint.cookie_parameters %} +{{ parameter.python_name }}={{ parameter.python_name }}, +{% endfor %} +{% endmacro %} + +{% macro docstring_content(endpoint, return_string, is_detailed) %} +{% if endpoint.summary %}{{ endpoint.summary | wordwrap(100)}} + +{% endif -%} +{%- if endpoint.description %} {{ endpoint.description | wordwrap(100) }} + +{% endif %} +{% if not endpoint.summary and not endpoint.description %} +{# Leave extra space so that Args or Returns isn't at the top #} + +{% endif %} +{% set all_parameters = endpoint.list_all_parameters() %} +{% if all_parameters %} +Args: + {% for parameter in all_parameters %} + {{ parameter.to_docstring() | wordwrap(90) | indent(8) }} + {% endfor %} + +{% endif %} +Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + +Returns: +{% if is_detailed %} + Response[{{ return_string }}] +{% else %} + {{ return_string }} +{% endif %} +{% endmacro %} + +{% macro docstring(endpoint, return_string, is_detailed) %} +{{ safe_docstring(docstring_content(endpoint, return_string, is_detailed)) }} +{% endmacro %} diff --git a/templates/endpoint_module.py.jinja b/templates/endpoint_module.py.jinja index e16b6eb..e04e9c0 100644 --- a/templates/endpoint_module.py.jinja +++ b/templates/endpoint_module.py.jinja @@ -68,7 +68,7 @@ def _get_kwargs_{{ endpoint.name }}(self, return _kwargs -def _parse_response_{{ endpoint.name }}(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[{{ return_string }}]: +def _parse_response_{{ endpoint.name }}(self, response: httpx.Response) -> Optional[{{ return_string }}]: {% for response in endpoint.responses %} if response.status_code == {{ response.status_code.value }}: {% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %} @@ -84,18 +84,18 @@ def _parse_response_{{ endpoint.name }}(self, *, client: Union[AuthenticatedClie return None {% endif %} {% endfor %} - if client.raise_on_unexpected_status: + if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None -def _build_response_{{ endpoint.name }}(self, *, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[{{ return_string }}]: +def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> Response[{{ return_string }}]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_{{ endpoint.name }}(client=client, response=response), + parsed=self._parse_response_{{ endpoint.name }}(response=response), ) async def asyncio_detailed_{{ endpoint.name }}(self, @@ -107,11 +107,11 @@ async def asyncio_detailed_{{ endpoint.name }}(self, {{ kwargs(endpoint, include_client=False) }} ) - response = await client.get_async_httpx_client().request( + response = await self.client.get_async_httpx_client().request( **kwargs ) - return self._build_response_{{ endpoint.name }}(client=client, response=response) + return self._build_response_{{ endpoint.name }}(response=response) {% if parsed_responses %} async def {{ endpoint.name }}(self, From be53b7dcdf7a18f9abae6bda0bcbd07f4cbf6baa Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 25 Dec 2024 19:41:47 +0300 Subject: [PATCH 078/296] add requirements --- pachca.py | 7 ------- requirements.txt | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 requirements.txt diff --git a/pachca.py b/pachca.py index 49e95b9..c54d946 100644 --- a/pachca.py +++ b/pachca.py @@ -1,11 +1,5 @@ import asyncio -from pachca_api_open_api_3_0_client.api.chats_and_channels.create_chat import ( - createChat, -) -from pachca_api_open_api_3_0_client.api.employees.get_employees import ( - getEmployees, -) from pachca_api_open_api_3_0_client.client import AuthenticatedClient, Pachca from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, @@ -31,7 +25,6 @@ async def main(): task2 = asyncio.create_task(pachca.createChat(body=chat_body)) task3 = asyncio.create_task(pachca.getEmployees()) - print('*' * 30) print(await task2) print('*' * 30) print(await task3) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..530696c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,27 @@ +annotated-types==0.7.0 +anyio==4.7.0 +attrs==24.3.0 +certifi==2024.12.14 +click==8.1.8 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +idna==3.10 +Jinja2==3.1.5 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdurl==0.1.2 +openapi-python-client==0.23.0 +pydantic==2.10.4 +pydantic_core==2.27.2 +Pygments==2.18.0 +python-dateutil==2.9.0.post0 +rich==13.9.4 +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.12 +ruff==0.8.4 +shellingham==1.5.4 +six==1.17.0 +sniffio==1.3.1 +typer==0.15.1 +typing_extensions==4.12.2 From 43e0a1c7cb0a377bd0a6d4fb95cd609adad0215c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 27 Dec 2024 14:18:48 +0300 Subject: [PATCH 079/296] message/reactions_fix --- openapi.yaml | 4 +- .../delete_message_reactions.py | 10 +- .../post_message_reactions.py | 10 +- .../pachca_api_open_api_3_0_client/client.py | 1550 ++++++++--------- pachca-api-open-api-3-0-client/pyproject.toml | 4 +- pachca.py | 2 +- 6 files changed, 790 insertions(+), 790 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index f4d8491..2ce97c6 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1265,7 +1265,7 @@ paths: required: true description: Уникальный идентификатор сообщения. schema: - type: string + type: integer requestBody: required: true content: @@ -1358,7 +1358,7 @@ paths: required: true description: Уникальный идентификатор сообщения. schema: - type: string + type: integer - name: code in: query required: true diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py index cb9aef6..8b717d9 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -11,7 +11,7 @@ def _get_kwargs_deleteMessageReactions( self, - id: str, + id: int, code: str, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -62,7 +62,7 @@ def _build_response_deleteMessageReactions( async def asyncio_detailed_deleteMessageReactions( self, - id: str, + id: int, code: str, ) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: """Удаление реакции @@ -71,7 +71,7 @@ async def asyncio_detailed_deleteMessageReactions( авторизованным пользователем. Args: - id (str): + id (int): code (str): Raises: @@ -94,7 +94,7 @@ async def asyncio_detailed_deleteMessageReactions( async def deleteMessageReactions( self, - id: str, + id: int, code: str, ) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: """Удаление реакции @@ -103,7 +103,7 @@ async def deleteMessageReactions( авторизованным пользователем. Args: - id (str): + id (int): code (str): Raises: diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py index d37f812..fb88d7d 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -13,7 +13,7 @@ def _get_kwargs_postMessageReactions( self, - id: str, + id: int, body: PostMessageReactionsBody, ) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -73,7 +73,7 @@ def _build_response_postMessageReactions( async def asyncio_detailed_postMessageReactions( self, - id: str, + id: int, body: PostMessageReactionsBody, ) -> Response[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] @@ -85,7 +85,7 @@ async def asyncio_detailed_postMessageReactions( уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - id (str): + id (int): body (PostMessageReactionsBody): Raises: @@ -108,7 +108,7 @@ async def asyncio_detailed_postMessageReactions( async def postMessageReactions( self, - id: str, + id: int, body: PostMessageReactionsBody, ) -> Optional[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] @@ -120,7 +120,7 @@ async def postMessageReactions( уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - id (str): + id (int): body (PostMessageReactionsBody): Raises: diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py index 4b1b8ee..aa5ed78 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -1,62 +1,62 @@ -from .models.get_chats_response_422 import GetChatsResponse422 -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .models.create_chat_response_404 import CreateChatResponse404 +from .models.get_chats_response_200 import GetChatsResponse200 from http import HTTPStatus -from .models.post_message_reactions_body import PostMessageReactionsBody -from .models.create_chat_response_422 import CreateChatResponse422 -from .models.post_tasks_body import PostTasksBody +from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .models.post_tasks_response_201 import PostTasksResponse201 +from .models.get_tags_response_400 import GetTagsResponse400 +from .models.get_chats_response_400 import GetChatsResponse400 +from .models.create_chat_response_400 import CreateChatResponse400 +from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .models.not_found import NotFound +from .types import UNSET +from .models.get_message_reactions_body import GetMessageReactionsBody +from .models.get_employee_response_200 import GetEmployeeResponse200 +from .models.get_list_message_response_200 import GetListMessageResponse200 from .models.create_message_response_201 import CreateMessageResponse201 +from .models.errors_code import ErrorsCode from .models.get_tags_response_200 import GetTagsResponse200 -from .models.get_tags_response_400 import GetTagsResponse400 -from .models.create_chat_body import CreateChatBody -from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from typing import Any from .models.get_employees_response_200 import GetEmployeesResponse200 +from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 from .models.get_tag_response_200 import GetTagResponse200 -from .models.get_chats_sortid import GetChatsSortid -from .types import UNSET -from .models.get_status_response_200 import GetStatusResponse200 -from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from .models.put_status_response_201 import PutStatusResponse201 -from .models.errors_code import ErrorsCode -from .models.direct_response import DirectResponse +from .models.get_chat_response_200 import GetChatResponse200 +from .models.get_message_response_200 import GetMessageResponse200 +from .models.create_chat_response_422 import CreateChatResponse422 +from typing import Optional +from .models.create_chat_response_201 import CreateChatResponse201 from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from .models.get_list_message_response_200 import GetListMessageResponse200 -from .models.post_members_to_chats_body import PostMembersToChatsBody -from .models.file_response import FileResponse -from .models.get_employee_response_200 import GetEmployeeResponse200 -from .models.create_thread_response_200 import CreateThreadResponse200 +from typing import Union from . import errors -from .models.bad_request import BadRequest -from .models.create_chat_response_404 import CreateChatResponse404 +from .models.error import Error from .models.put_messages_id_body import PutMessagesIdBody from .models.get_tag_response_404 import GetTagResponse404 -from .models.get_message_reactions_body import GetMessageReactionsBody +from typing import cast +from .models.direct_response import DirectResponse +from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from .types import Unset +from .models.post_tasks_body import PostTasksBody +from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .models.get_chats_response_404 import GetChatsResponse404 +from .models.get_status_response_200 import GetStatusResponse200 +from .models.get_chats_sortid import GetChatsSortid +from .types import Response +from .models.query_status import QueryStatus +from .models.bad_request import BadRequest +from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .models.post_members_to_chats_body import PostMembersToChatsBody +from .models.create_chat_body import CreateChatBody from .models.create_message_body import CreateMessageBody from .models.get_chats_availability import GetChatsAvailability -from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .models.get_chats_response_400 import GetChatsResponse400 -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 from .models.post_tags_to_chats_body import PostTagsToChatsBody +from .models.create_thread_response_200 import CreateThreadResponse200 +from .models.post_tasks_response_400 import PostTasksResponse400 from .models.get_chat_response_404 import GetChatResponse404 -from typing import Union -from .models.get_chat_response_200 import GetChatResponse200 -from .models.create_chat_response_400 import CreateChatResponse400 -from .models.get_chats_response_404 import GetChatsResponse404 -from .models.create_chat_response_201 import CreateChatResponse201 -from .models.query_status import QueryStatus +from .models.get_chats_response_422 import GetChatsResponse422 from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from typing import cast -from .models.error import Error -from .models.post_tasks_response_201 import PostTasksResponse201 -from .models.not_found import NotFound -from .models.post_tasks_response_400 import PostTasksResponse400 -from .models.get_message_response_200 import GetMessageResponse200 -from .models.get_chats_response_200 import GetChatsResponse200 -from .types import Response -from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from typing import Any -from typing import Optional -from .types import Unset +from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .models.file_response import FileResponse +from .models.post_message_reactions_body import PostMessageReactionsBody +from .models.put_status_response_201 import PutStatusResponse201 import datetime import ssl @@ -338,146 +338,364 @@ def __init__(self, base_url, token): - def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} + def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 + def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + return response_201 if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) + response_400 = CreateChatResponse400.from_dict(response.json()) return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + return response_422 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) + def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) - async def asyncio_detailed_createThread(self, id: int) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда + async def asyncio_detailed_createChat(self, body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ Args: - id (int): + body (CreateChatBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, CreateThreadResponse200, NotFound]] - """ - kwargs = self._get_kwargs_createThread(id=id) + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + kwargs = self._get_kwargs_createChat(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(response=response) + return self._build_response_createChat(response=response) - async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда + async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ Args: - id (int): + body (CreateChatBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - return (await self.asyncio_detailed_createThread(id=id)).parsed + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + return (await self.asyncio_detailed_createChat(body=body)).parsed - def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['entity_type'] = entity_type - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} + def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} return _kwargs - def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + response_200 = GetChatResponse200.from_dict(response.json()) return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) + def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) - async def asyncio_detailed_getCommonMethods(self, entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей + async def asyncio_detailed_getChat(self, id: int) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. Args: - entity_type (str): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetCommonMethodsResponse200]] + Response[Union[GetChatResponse200, GetChatResponse404]] """ - kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) + kwargs = self._get_kwargs_getChat(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(response=response) + return self._build_response_getChat(response=response) - async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей + async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. Args: - entity_type (str): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetCommonMethodsResponse200] + Union[GetChatResponse200, GetChatResponse404] """ - return (await self.asyncio_detailed_getCommonMethods(entity_type=entity_type)).parsed + return (await self.asyncio_detailed_getChat(id=id)).parsed - def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} - _body = body.to_multipart() - _kwargs['files'] = _body - _kwargs['headers'] = headers + def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + params['sort[id]'] = json_sortid + params['per'] = per + params['page'] = page + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + params['availability'] = json_availability + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params['last_message_at_after'] = json_last_message_at_after + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params['last_message_at_before'] = json_last_message_at_before + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} return _kwargs - def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None + def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + return response_422 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) + def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) - async def asyncio_detailed_getDirectUrl(self, body: DirectResponse) -> Response[Any]: + async def asyncio_detailed_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + """ + kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChats(response=response) + + async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + return (await self.asyncio_detailed_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed + + def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} + return _kwargs + + def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) + + async def asyncio_detailed_createThread(self, id: int) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + kwargs = self._get_kwargs_createThread(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createThread(response=response) + + async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + return (await self.asyncio_detailed_createThread(id=id)).parsed + + def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['entity_type'] = entity_type + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} + return _kwargs + + def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) + + async def asyncio_detailed_getCommonMethods(self, entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[BadRequest, GetCommonMethodsResponse200]] + """ + kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getCommonMethods(response=response) + + async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + return (await self.asyncio_detailed_getCommonMethods(entity_type=entity_type)).parsed + + def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} + _body = body.to_multipart() + _kwargs['files'] = _body + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) + + async def asyncio_detailed_getDirectUrl(self, body: DirectResponse) -> Response[Any]: """Получение URL для загрузки Отправляет запрос для получения URL для безопасной загрузки файла. @@ -542,78 +760,123 @@ async def getUploads(self) -> Optional[FileResponse]: """ return (await self.asyncio_detailed_getUploads()).parsed - def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} return _kwargs - def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: if response.status_code == 200: - response_200 = PutMessagesIdResponse200.from_dict(response.json()) + response_200 = GetEmployeeResponse200.from_dict(response.json()) return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) + response_404 = NotFound.from_dict(response.json()) return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) + def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) - async def asyncio_detailed_put_messages_id(self, id: int, body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения + async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике - Метод для редактирования сообщения или комментария. + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. Args: id (int): - body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + Response[Union[GetEmployeeResponse200, NotFound]] """ - kwargs = self._get_kwargs_put_messages_id(id=id, body=body) + kwargs = self._get_kwargs_getEmployee(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(response=response) + return self._build_response_getEmployee(response=response) - async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения + async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике - Метод для редактирования сообщения или комментария. + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. Args: id (int): - body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[PutMessagesIdResponse200, list['ErrorsCode']] + Union[GetEmployeeResponse200, NotFound] """ - return (await self.asyncio_detailed_put_messages_id(id=id, body=body)).parsed + return (await self.asyncio_detailed_getEmployee(id=id)).parsed + + def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params['query'] = query + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} + return _kwargs + + def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) + + async def asyncio_detailed_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[GetEmployeesResponse200] + """ + kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployees(response=response) + + async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + return (await self.asyncio_detailed_getEmployees(per=per, page=page, query=query)).parsed def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -706,65 +969,6 @@ async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequ """ return (await self.asyncio_detailed_createMessage(body=body)).parsed - def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} - return _kwargs - - def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) - - async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetMessageResponse200, NotFound]] - """ - kwargs = self._get_kwargs_getMessage(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(response=response) - - async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetMessageResponse200, NotFound] - """ - return (await self.asyncio_detailed_getMessage(id=id)).parsed - def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} params['chat_id'] = chat_id @@ -842,79 +1046,77 @@ async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Un """ return (await self.asyncio_detailed_getListMessage(chat_id=chat_id, per=per, page=page)).parsed - def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} return _kwargs - def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 + def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) + def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) - async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала + async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении - Метод для добавления тегов в состав участников беседы или канала. + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. Args: - id (int): Example: 533. - body (PostTagsToChatsBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[GetMessageResponse200, NotFound]] """ - kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) + kwargs = self._get_kwargs_getMessage(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(response=response) + return self._build_response_getMessage(response=response) - async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала + async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении - Метод для добавления тегов в состав участников беседы или канала. + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. Args: - id (int): Example: 533. - body (PostTagsToChatsBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[GetMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed + return (await self.asyncio_detailed_getMessage(id=id)).parsed - def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} + def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: if response.status_code == 200: - response_200 = cast(Any, None) + response_200 = PutMessagesIdResponse200.from_dict(response.json()) return response_200 if response.status_code == 400: response_400 = [] @@ -935,328 +1137,351 @@ def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Opt else: return None - def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) + def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) - async def asyncio_detailed_delete_chats_id_leave(self, id: int) -> Response[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала + async def asyncio_detailed_put_messages_id(self, id: int, body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения - Метод для самостоятельного выхода из беседы или канала. + Метод для редактирования сообщения или комментария. Args: id (int): + body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_delete_chats_id_leave(id=id) + kwargs = self._get_kwargs_put_messages_id(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(response=response) + return self._build_response_put_messages_id(response=response) - async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала + async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения - Метод для самостоятельного выхода из беседы или канала. + Метод для редактирования сообщения или комментария. Args: id (int): + body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[PutMessagesIdResponse200, list['ErrorsCode']] """ - return (await self.asyncio_detailed_delete_chats_id_leave(id=id)).parsed + return (await self.asyncio_detailed_put_messages_id(id=id, body=body)).parsed - def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['code'] = code + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} return _kwargs - def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 + def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) + def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) - async def asyncio_detailed_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников + async def asyncio_detailed_deleteMessageReactions(self, id: int, code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции - Метод для добавления пользователей в состав участников беседы или канала. + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. Args: - id (int): Example: 533. - body (PostMembersToChatsBody): + id (int): + code (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] """ - kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) + kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(response=response) + return self._build_response_deleteMessageReactions(response=response) - async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников + async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции - Метод для добавления пользователей в состав участников беседы или канала. + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. Args: - id (int): Example: 533. - body (PostMembersToChatsBody): + id (int): + code (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] """ - return (await self.asyncio_detailed_postMembersToChats(id=id, body=body)).parsed + return (await self.asyncio_detailed_deleteMessageReactions(id=id, code=code)).parsed - def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} + def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) return response_200 if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) + response_404 = NotFound.from_dict(response.json()) return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) + def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) - async def asyncio_detailed_getChat(self, id: int) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале + async def asyncio_detailed_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. Args: id (int): + body (GetMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatResponse200, GetChatResponse404]] + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] """ - kwargs = self._get_kwargs_getChat(id=id) + kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(response=response) + return self._build_response_getMessageReactions(response=response) - async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале + async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. Args: id (int): + body (GetMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetChatResponse200, GetChatResponse404] + Union[BadRequest, GetMessageReactionsResponse200, NotFound] """ - return (await self.asyncio_detailed_getChat(id=id)).parsed + return (await self.asyncio_detailed_getMessageReactions(id=id, body=body)).parsed - def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: + def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} _body = body.to_dict() _kwargs['json'] = _body headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - return response_201 + def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + return response_403 if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - return response_422 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) + def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - async def asyncio_detailed_createChat(self, body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал + async def asyncio_detailed_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - body (CreateChatBody): + id (int): + body (PostMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] - """ - kwargs = self._get_kwargs_createChat(body=body) + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + """ + kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(response=response) + return self._build_response_postMessageReactions(response=response) - async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал + async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - body (CreateChatBody): + id (int): + body (PostMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - return (await self.asyncio_detailed_createChat(body=body)).parsed + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + return (await self.asyncio_detailed_postMessageReactions(id=id, body=body)).parsed - def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - params['sort[id]'] = json_sortid - params['per'] = per - params['page'] = page - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - params['availability'] = json_availability - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params['last_message_at_after'] = json_last_message_at_after - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params['last_message_at_before'] = json_last_message_at_before - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} + def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - return response_200 + def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + return response_201 if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) + response_400 = PostTasksResponse400.from_dict(response.json()) return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - return response_422 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) + def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) - async def asyncio_detailed_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов + async def asyncio_detailed_post_tasks(self, body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. - Получения списка бесед и каналов по заданным параметрам. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): + body (PostTasksBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + Response[Union[PostTasksResponse201, PostTasksResponse400]] """ - kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + kwargs = self._get_kwargs_post_tasks(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(response=response) + return self._build_response_post_tasks(response=response) - async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов + async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. - Получения списка бесед и каналов по заданным параметрам. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): + body (PostTasksBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + Union[PostTasksResponse201, PostTasksResponse400] """ - return (await self.asyncio_detailed_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed + return (await self.asyncio_detailed_post_tasks(body=body)).parsed + + def _get_kwargs_delStatus(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} + return _kwargs + + def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) + + async def asyncio_detailed_delStatus(self) -> Response[Any]: + """удаление своего статуса + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + kwargs = self._get_kwargs_delStatus() + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_delStatus(response=response) def _get_kwargs_getStatus(self) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} @@ -1364,98 +1589,6 @@ async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutSt """ return (await self.asyncio_detailed_putStatus(body=body)).parsed - def _get_kwargs_delStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} - return _kwargs - - def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) - - async def asyncio_detailed_delStatus(self) -> Response[Any]: - """удаление своего статуса - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - kwargs = self._get_kwargs_delStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delStatus(response=response) - - def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} - return _kwargs - - def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - - async def asyncio_detailed_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetTagsResponse200, GetTagsResponse400]] - """ - kwargs = self._get_kwargs_getTags(per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(response=response) - - async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagsResponse200, GetTagsResponse400] - """ - return (await self.asyncio_detailed_getTags(per=per, page=page)).parsed - def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} return _kwargs @@ -1511,58 +1644,36 @@ async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagRespo """ return (await self.asyncio_detailed_getTag(id=id)).parsed - def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} params['per'] = per params['page'] = page params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} return _kwargs - def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + response_200 = GetTagsResponse200.from_dict(response.json()) return response_200 if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) + response_400 = GetTagsResponse400.from_dict(response.json()) return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - - async def asyncio_detailed_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, GetTagsEmployeesResponse200]] - """ - kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(response=response) + def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега + async def asyncio_detailed_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников - Метод для получения актуального списка сотрудников тега. + Метод для получения актуального списка тегов сотрудников. Args: - id (int): - per (Union[Unset, int]): Default: 25. + per (Union[Unset, int]): Default: 50. page (Union[Unset, int]): Default: 1. Raises: @@ -1570,168 +1681,42 @@ async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetTagsEmployeesResponse200] - """ - return (await self.asyncio_detailed_getTagsEmployees(id=id, per=per, page=page)).parsed - - def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - if response.status_code == 201: - response_201 = PostTasksResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = PostTasksResponse400.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) - - async def asyncio_detailed_post_tasks(self, body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (PostTasksBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[PostTasksResponse201, PostTasksResponse400]] - """ - kwargs = self._get_kwargs_post_tasks(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(response=response) - - async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (PostTasksBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PostTasksResponse201, PostTasksResponse400] - """ - return (await self.asyncio_detailed_post_tasks(body=body)).parsed - - def _get_kwargs_postMessageReactions(self, id: str, body: PostMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - - async def asyncio_detailed_postMessageReactions(self, id: str, body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (str): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + Response[Union[GetTagsResponse200, GetTagsResponse400]] """ - kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) + kwargs = self._get_kwargs_getTags(per=per, page=page) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(response=response) + return self._build_response_getTags(response=response) - async def postMessageReactions(self, id: str, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции + async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. + Метод для получения актуального списка тегов сотрудников. Args: - id (str): - body (PostMessageReactionsBody): + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + Union[GetTagsResponse200, GetTagsResponse400] """ - return (await self.asyncio_detailed_postMessageReactions(id=id, body=body)).parsed + return (await self.asyncio_detailed_getTags(per=per, page=page)).parsed - def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} return _kwargs - def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 @@ -1740,230 +1725,245 @@ def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optio else: return None - def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) + def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - async def asyncio_detailed_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. + async def asyncio_detailed_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. + Метод для получения актуального списка сотрудников тега. Args: id (int): - body (GetMessageReactionsBody): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + Response[Union[BadRequest, GetTagsEmployeesResponse200]] """ - kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) + kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(response=response) + return self._build_response_getTagsEmployees(response=response) - async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. + async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. + Метод для получения актуального списка сотрудников тега. Args: id (int): - body (GetMessageReactionsBody): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] + Union[BadRequest, GetTagsEmployeesResponse200] """ - return (await self.asyncio_detailed_getMessageReactions(id=id, body=body)).parsed + return (await self.asyncio_detailed_getTagsEmployees(id=id, per=per, page=page)).parsed - def _get_kwargs_deleteMessageReactions(self, id: str, code: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['code'] = code - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} + def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} return _kwargs - def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 + def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) return response_400 if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) + def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) - async def asyncio_detailed_deleteMessageReactions(self, id: str, code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции + async def asyncio_detailed_delete_chats_id_leave(self, id: int) -> Response[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. + Метод для самостоятельного выхода из беседы или канала. Args: - id (str): - code (str): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) + kwargs = self._get_kwargs_delete_chats_id_leave(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(response=response) + return self._build_response_delete_chats_id_leave(response=response) - async def deleteMessageReactions(self, id: str, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции + async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. + Метод для самостоятельного выхода из беседы или канала. Args: - id (str): - code (str): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_deleteMessageReactions(id=id, code=code)).parsed + return (await self.asyncio_detailed_delete_chats_id_leave(id=id)).parsed - def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params['query'] = query - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} + def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: - if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) - return response_200 + def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) + def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) - async def asyncio_detailed_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании + async def asyncio_detailed_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников - Fetch a paginated list of employees with optional filtering by query. + Метод для добавления пользователей в состав участников беседы или канала. Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): + id (int): Example: 533. + body (PostMembersToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[GetEmployeesResponse200] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) + kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(response=response) + return self._build_response_postMembersToChats(response=response) - async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании + async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников - Fetch a paginated list of employees with optional filtering by query. + Метод для добавления пользователей в состав участников беседы или канала. Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): + id (int): Example: 533. + body (PostMembersToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - GetEmployeesResponse200 + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_getEmployees(per=per, page=page, query=query)).parsed + return (await self.asyncio_detailed_postMembersToChats(id=id, body=body)).parsed - def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} + def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 + def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) + def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) - async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике + async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + Метод для добавления тегов в состав участников беседы или канала. Args: - id (int): + id (int): Example: 533. + body (PostTagsToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetEmployeeResponse200, NotFound]] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_getEmployee(id=id) + kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(response=response) + return self._build_response_postTagsToChats(response=response) - async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике + async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + Метод для добавления тегов в состав участников беседы или канала. Args: - id (int): + id (int): Example: 533. + body (PostTagsToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetEmployeeResponse200, NotFound] + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_getEmployee(id=id)).parsed + return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pyproject.toml b/pachca-api-open-api-3-0-client/pyproject.toml index da5dcfa..29f8de8 100644 --- a/pachca-api-open-api-3-0-client/pyproject.toml +++ b/pachca-api-open-api-3-0-client/pyproject.toml @@ -12,8 +12,8 @@ include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] [tool.poetry.dependencies] python = "^3.9" -httpx = ">=0.20.0,<0.29.0" -attrs = ">=22.2.0" +httpx = ">=0.20.0,<0.28.0" +attrs = ">=21.3.0" python-dateutil = "^2.8.0" [build-system] diff --git a/pachca.py b/pachca.py index c54d946..061e76d 100644 --- a/pachca.py +++ b/pachca.py @@ -31,4 +31,4 @@ async def main(): if __name__ == '__main__': - asyncio.run(main()) + asyncio.run(main()) \ No newline at end of file From 136506de14ed70f79563ea060d79be23358a64fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 27 Dec 2024 19:16:57 +0300 Subject: [PATCH 080/296] base_url fix --- .../pachca_api_open_api_3_0_client/client.py | 111 ++++++++++-------- pachca.py | 10 +- templates/client.py.jinja | 19 ++- 3 files changed, 76 insertions(+), 64 deletions(-) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py index aa5ed78..5091094 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -1,62 +1,62 @@ -from .models.create_chat_response_404 import CreateChatResponse404 -from .models.get_chats_response_200 import GetChatsResponse200 -from http import HTTPStatus -from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from typing import cast from .models.post_tasks_response_201 import PostTasksResponse201 -from .models.get_tags_response_400 import GetTagsResponse400 -from .models.get_chats_response_400 import GetChatsResponse400 -from .models.create_chat_response_400 import CreateChatResponse400 -from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from .models.not_found import NotFound -from .types import UNSET -from .models.get_message_reactions_body import GetMessageReactionsBody -from .models.get_employee_response_200 import GetEmployeeResponse200 from .models.get_list_message_response_200 import GetListMessageResponse200 +from .models.post_tags_to_chats_body import PostTagsToChatsBody +from .models.create_thread_response_200 import CreateThreadResponse200 +from .models.get_tag_response_404 import GetTagResponse404 +from http import HTTPStatus +from .models.create_chat_response_404 import CreateChatResponse404 +from .models.create_chat_response_422 import CreateChatResponse422 +from .models.get_tag_response_200 import GetTagResponse200 +from .models.get_chats_response_422 import GetChatsResponse422 from .models.create_message_response_201 import CreateMessageResponse201 +from .models.create_chat_response_400 import CreateChatResponse400 +from .models.post_tasks_body import PostTasksBody +from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .models.get_chats_response_400 import GetChatsResponse400 +from .models.get_chats_availability import GetChatsAvailability from .models.errors_code import ErrorsCode -from .models.get_tags_response_200 import GetTagsResponse200 -from typing import Any -from .models.get_employees_response_200 import GetEmployeesResponse200 -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .models.get_tag_response_200 import GetTagResponse200 -from .models.get_chat_response_200 import GetChatResponse200 -from .models.get_message_response_200 import GetMessageResponse200 -from .models.create_chat_response_422 import CreateChatResponse422 -from typing import Optional -from .models.create_chat_response_201 import CreateChatResponse201 from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from typing import Union -from . import errors -from .models.error import Error -from .models.put_messages_id_body import PutMessagesIdBody -from .models.get_tag_response_404 import GetTagResponse404 -from typing import cast -from .models.direct_response import DirectResponse -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from .types import Unset -from .models.post_tasks_body import PostTasksBody from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .models.put_status_response_201 import PutStatusResponse201 from .models.get_chats_response_404 import GetChatsResponse404 -from .models.get_status_response_200 import GetStatusResponse200 -from .models.get_chats_sortid import GetChatsSortid from .types import Response -from .models.query_status import QueryStatus -from .models.bad_request import BadRequest -from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .models.get_message_reactions_body import GetMessageReactionsBody +from typing import Union +from .models.get_chats_sortid import GetChatsSortid +from .models.get_chat_response_200 import GetChatResponse200 +from .models.error import Error +from .models.get_employee_response_200 import GetEmployeeResponse200 +from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .models.get_employees_response_200 import GetEmployeesResponse200 +from .models.create_chat_response_201 import CreateChatResponse201 +from . import errors from .models.post_members_to_chats_body import PostMembersToChatsBody -from .models.create_chat_body import CreateChatBody -from .models.create_message_body import CreateMessageBody -from .models.get_chats_availability import GetChatsAvailability -from .models.post_tags_to_chats_body import PostTagsToChatsBody -from .models.create_thread_response_200 import CreateThreadResponse200 -from .models.post_tasks_response_400 import PostTasksResponse400 +from typing import Any +from .models.get_message_response_200 import GetMessageResponse200 +from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 from .models.get_chat_response_404 import GetChatResponse404 -from .models.get_chats_response_422 import GetChatsResponse422 +from .models.not_found import NotFound +from .models.direct_response import DirectResponse +from .models.get_tags_response_400 import GetTagsResponse400 +from .models.query_status import QueryStatus +from .models.post_tasks_response_400 import PostTasksResponse400 +from .models.bad_request import BadRequest from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.file_response import FileResponse +from .models.get_chats_response_200 import GetChatsResponse200 +from .models.create_message_body import CreateMessageBody +from .types import Unset +from .models.get_status_response_200 import GetStatusResponse200 from .models.post_message_reactions_body import PostMessageReactionsBody -from .models.put_status_response_201 import PutStatusResponse201 +from typing import Optional +from .types import UNSET +from .models.file_response import FileResponse +from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .models.get_tags_response_200 import GetTagsResponse200 +from .models.put_messages_id_body import PutMessagesIdBody +from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from .models.create_chat_body import CreateChatBody import datetime import ssl @@ -99,7 +99,11 @@ class Client: """ raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") + _base_url: str = field( + default="https://api.pachca.com/api/shared/v1", + kw_only=True, + alias="base_url" + ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") @@ -227,7 +231,11 @@ class AuthenticatedClient: """ raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") + _base_url: str = field( + default="https://api.pachca.com/api/shared/v1", + kw_only=True, + alias="base_url" + ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") @@ -333,8 +341,8 @@ async def __aexit__(self, *args: Any, **kwargs: Any) -> None: class Pachca: """Главный класс библиотеки.""" - def __init__(self, base_url, token): - self.client = AuthenticatedClient(base_url=base_url, token=token) + def __init__(self, token): + self.client = AuthenticatedClient(token=token) @@ -1966,4 +1974,5 @@ async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[ """ return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed + \ No newline at end of file diff --git a/pachca.py b/pachca.py index 061e76d..6fad188 100644 --- a/pachca.py +++ b/pachca.py @@ -1,23 +1,17 @@ import asyncio -from pachca_api_open_api_3_0_client.client import AuthenticatedClient, Pachca +from pachca_api_open_api_3_0_client.client import Pachca from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, ) from pachca_api_open_api_3_0_client.models.query_chat import QueryChat -client = AuthenticatedClient( - base_url='https://api.pachca.com/api/shared/v1', - token='35KekGygDNiFwtPpqUe44CaEZ_EVL17ycYRJrMnvHOs', -) - query_chat = QueryChat(name='test') chat_body = CreateChatBody(chat=query_chat) pachca = Pachca( - base_url='https://api.pachca.com/api/shared/v1', - token='35KekGygDNiFwtPpqUe44CaEZ_EVL17ycYRJrMnvHOs', + token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', ) diff --git a/templates/client.py.jinja b/templates/client.py.jinja index 8c11934..c11a384 100644 --- a/templates/client.py.jinja +++ b/templates/client.py.jinja @@ -39,7 +39,11 @@ class Client: """ {% macro attributes() %} raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") + _base_url: str = field( + default="https://api.pachca.com/api/shared/v1", + kw_only=True, + alias="base_url" + ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") @@ -153,7 +157,11 @@ class AuthenticatedClient: """ raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") + _base_url: str = field( + default="https://api.pachca.com/api/shared/v1", + kw_only=True, + alias="base_url" + ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") @@ -259,11 +267,12 @@ class AuthenticatedClient: class Pachca: """Главный класс библиотеки.""" - def __init__(self, base_url, token): - self.client = AuthenticatedClient(base_url=base_url, token=token) + def __init__(self, token): + self.client = AuthenticatedClient(token=token) {% if endpoints %} {% for endpoint in endpoints %} {{ endpoint | indent(4, first=Fasle) }} {% endfor %} - {% endif %} \ No newline at end of file + {% endif %} + \ No newline at end of file From ad8785bfb742f3871a12882c340a8763e0a28e00 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Dec 2024 22:55:58 +0300 Subject: [PATCH 081/296] remove base_url from Pachca --- .../pachca_api_open_api_3_0_client/client.py | 1722 ++++++++--------- pachca-api-open-api-3-0-client/pyproject.toml | 4 +- 2 files changed, 863 insertions(+), 863 deletions(-) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py index 5091094..d268cdf 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -1,62 +1,62 @@ -from typing import cast -from .models.post_tasks_response_201 import PostTasksResponse201 -from .models.get_list_message_response_200 import GetListMessageResponse200 +from .models.get_employees_response_200 import GetEmployeesResponse200 +from .models.bad_request import BadRequest +from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from .models.create_chat_response_400 import CreateChatResponse400 +from .models.get_chats_response_400 import GetChatsResponse400 +from .models.get_message_response_200 import GetMessageResponse200 from .models.post_tags_to_chats_body import PostTagsToChatsBody -from .models.create_thread_response_200 import CreateThreadResponse200 -from .models.get_tag_response_404 import GetTagResponse404 -from http import HTTPStatus +from .models.direct_response import DirectResponse +from .models.create_message_body import CreateMessageBody +from .models.post_members_to_chats_body import PostMembersToChatsBody +from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from typing import Any from .models.create_chat_response_404 import CreateChatResponse404 -from .models.create_chat_response_422 import CreateChatResponse422 -from .models.get_tag_response_200 import GetTagResponse200 +from .models.create_chat_response_201 import CreateChatResponse201 +from .models.file_response import FileResponse +from .models.get_chat_response_200 import GetChatResponse200 from .models.get_chats_response_422 import GetChatsResponse422 -from .models.create_message_response_201 import CreateMessageResponse201 -from .models.create_chat_response_400 import CreateChatResponse400 -from .models.post_tasks_body import PostTasksBody -from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from .models.get_chats_response_400 import GetChatsResponse400 -from .models.get_chats_availability import GetChatsAvailability -from .models.errors_code import ErrorsCode -from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .models.put_status_response_201 import PutStatusResponse201 from .models.get_chats_response_404 import GetChatsResponse404 -from .types import Response -from .models.get_message_reactions_body import GetMessageReactionsBody -from typing import Union -from .models.get_chats_sortid import GetChatsSortid -from .models.get_chat_response_200 import GetChatResponse200 -from .models.error import Error +from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .models.put_messages_id_body import PutMessagesIdBody from .models.get_employee_response_200 import GetEmployeeResponse200 -from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 -from .models.get_employees_response_200 import GetEmployeesResponse200 -from .models.create_chat_response_201 import CreateChatResponse201 -from . import errors -from .models.post_members_to_chats_body import PostMembersToChatsBody -from typing import Any -from .models.get_message_response_200 import GetMessageResponse200 +from .models.error import Error +from .models.put_messages_id_response_200 import PutMessagesIdResponse200 +from .models.create_chat_response_422 import CreateChatResponse422 +from .types import UNSET +from .models.post_tasks_response_201 import PostTasksResponse201 +from http import HTTPStatus from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 from .models.get_chat_response_404 import GetChatResponse404 +from .models.get_status_response_200 import GetStatusResponse200 +from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from . import errors +from .models.get_tag_response_404 import GetTagResponse404 +from .models.get_chats_sortid import GetChatsSortid +from .models.post_tasks_response_400 import PostTasksResponse400 +from .models.create_chat_body import CreateChatBody +from .models.get_chats_availability import GetChatsAvailability +from .models.get_tag_response_200 import GetTagResponse200 +from .models.create_thread_response_200 import CreateThreadResponse200 +from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .models.get_list_message_response_200 import GetListMessageResponse200 +from .models.errors_code import ErrorsCode +from typing import Optional +from .models.put_status_response_201 import PutStatusResponse201 from .models.not_found import NotFound -from .models.direct_response import DirectResponse -from .models.get_tags_response_400 import GetTagsResponse400 +from .types import Unset +from typing import cast +from .models.get_tags_response_200 import GetTagsResponse200 from .models.query_status import QueryStatus -from .models.post_tasks_response_400 import PostTasksResponse400 -from .models.bad_request import BadRequest -from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from .models.post_tasks_body import PostTasksBody from .models.get_chats_response_200 import GetChatsResponse200 -from .models.create_message_body import CreateMessageBody -from .types import Unset -from .models.get_status_response_200 import GetStatusResponse200 +from .models.get_tags_response_400 import GetTagsResponse400 +from .types import Response +from typing import Union +from .models.create_message_response_201 import CreateMessageResponse201 +from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .models.get_message_reactions_body import GetMessageReactionsBody +from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 from .models.post_message_reactions_body import PostMessageReactionsBody -from typing import Optional -from .types import UNSET -from .models.file_response import FileResponse -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .models.get_tags_response_200 import GetTagsResponse200 -from .models.put_messages_id_body import PutMessagesIdBody -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from .models.create_chat_body import CreateChatBody import datetime import ssl @@ -346,435 +346,381 @@ def __init__(self, token): - def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} return _kwargs - def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) - return response_400 + def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + return response_200 if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) + response_404 = NotFound.from_dict(response.json()) return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - return response_422 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) + def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) - async def asyncio_detailed_createChat(self, body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал + async def asyncio_detailed_createThread(self, id: int) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. Args: - body (CreateChatBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] - """ - kwargs = self._get_kwargs_createChat(body=body) + Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + """ + kwargs = self._get_kwargs_createThread(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(response=response) + return self._build_response_createThread(response=response) - async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал + async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. Args: - body (CreateChatBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - return (await self.asyncio_detailed_createChat(body=body)).parsed + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + return (await self.asyncio_detailed_createThread(id=id)).parsed - def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} + def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['entity_type'] = entity_type + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} return _kwargs - def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) return response_200 - if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) - return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) + def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) - async def asyncio_detailed_getChat(self, id: int) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале + async def asyncio_detailed_getCommonMethods(self, entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. Args: - id (int): + entity_type (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatResponse200, GetChatResponse404]] + Response[Union[BadRequest, GetCommonMethodsResponse200]] """ - kwargs = self._get_kwargs_getChat(id=id) + kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(response=response) + return self._build_response_getCommonMethods(response=response) - async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале + async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. Args: - id (int): + entity_type (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetChatResponse200, GetChatResponse404] + Union[BadRequest, GetCommonMethodsResponse200] """ - return (await self.asyncio_detailed_getChat(id=id)).parsed + return (await self.asyncio_detailed_getCommonMethods(entity_type=entity_type)).parsed - def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - params['sort[id]'] = json_sortid - params['per'] = per - params['page'] = page - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - params['availability'] = json_availability - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params['last_message_at_after'] = json_last_message_at_after - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params['last_message_at_before'] = json_last_message_at_before - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} + def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} + _body = body.to_multipart() + _kwargs['files'] = _body + _kwargs['headers'] = headers return _kwargs - def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) + def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) + def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) - async def asyncio_detailed_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов + async def asyncio_detailed_getDirectUrl(self, body: DirectResponse) -> Response[Any]: + """Получение URL для загрузки - Получения списка бесед и каналов по заданным параметрам. + Отправляет запрос для получения URL для безопасной загрузки файла. Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): + body (DirectResponse): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + Response[Any] """ - kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + kwargs = self._get_kwargs_getDirectUrl(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(response=response) - - async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - return (await self.asyncio_detailed_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed + return self._build_response_getDirectUrl(response=response) - def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} + def _get_kwargs_getUploads(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} return _kwargs - def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) + response_200 = FileResponse.from_dict(response.json()) return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) + def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) - async def asyncio_detailed_createThread(self, id: int) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. + async def asyncio_detailed_getUploads(self) -> Response[FileResponse]: + """Получение подписи и ключа для загрузки файла - Args: - id (int): + Возвращает параметры, необходимые для безопасной загрузки файла. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + Response[FileResponse] """ - kwargs = self._get_kwargs_createThread(id=id) + kwargs = self._get_kwargs_getUploads() response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(response=response) + return self._build_response_getUploads(response=response) - async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. + async def getUploads(self) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла - Args: - id (int): + Возвращает параметры, необходимые для безопасной загрузки файла. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] + FileResponse """ - return (await self.asyncio_detailed_createThread(id=id)).parsed + return (await self.asyncio_detailed_getUploads()).parsed - def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['entity_type'] = entity_type - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} + def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + response_200 = PutMessagesIdResponse200.from_dict(response.json()) return response_200 if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) + def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) - async def asyncio_detailed_getCommonMethods(self, entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей + async def asyncio_detailed_put_messages_id(self, id: int, body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. + Метод для редактирования сообщения или комментария. Args: - entity_type (str): + id (int): + body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetCommonMethodsResponse200]] + Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) + kwargs = self._get_kwargs_put_messages_id(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(response=response) + return self._build_response_put_messages_id(response=response) - async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей + async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: + """Редактирование сообщения - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. + Метод для редактирования сообщения или комментария. Args: - entity_type (str): + id (int): + body (PutMessagesIdBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetCommonMethodsResponse200] + Union[PutMessagesIdResponse200, list['ErrorsCode']] """ - return (await self.asyncio_detailed_getCommonMethods(entity_type=entity_type)).parsed + return (await self.asyncio_detailed_put_messages_id(id=id, body=body)).parsed - def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: + def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} - _body = body.to_multipart() - _kwargs['files'] = _body + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None + def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + response_404.append(componentsschemas_errors_item) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) + def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) - async def asyncio_detailed_getDirectUrl(self, body: DirectResponse) -> Response[Any]: - """Получение URL для загрузки + async def asyncio_detailed_createMessage(self, body: CreateMessageBody) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + """создание нового сообщения - Отправляет запрос для получения URL для безопасной загрузки файла. + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. Args: - body (DirectResponse): + body (CreateMessageBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any] + Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] """ - kwargs = self._get_kwargs_getDirectUrl(body=body) + kwargs = self._get_kwargs_createMessage(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getDirectUrl(response=response) - - def _get_kwargs_getUploads(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} - return _kwargs - - def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: - if response.status_code == 200: - response_200 = FileResponse.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) + return self._build_response_createMessage(response=response) - async def asyncio_detailed_getUploads(self) -> Response[FileResponse]: - """Получение подписи и ключа для загрузки файла + async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + """создание нового сообщения - Возвращает параметры, необходимые для безопасной загрузки файла. + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. + При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. - Returns: - Response[FileResponse] - """ - kwargs = self._get_kwargs_getUploads() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getUploads(response=response) - - async def getUploads(self) -> Optional[FileResponse]: - """Получение подписи и ключа для загрузки файла + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. - Возвращает параметры, необходимые для безопасной загрузки файла. + Args: + body (CreateMessageBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - FileResponse + Union[BadRequest, CreateMessageResponse201, list['Error']] """ - return (await self.asyncio_detailed_getUploads()).parsed + return (await self.asyncio_detailed_createMessage(body=body)).parsed - def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} + def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} return _kwargs - def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) + response_200 = GetMessageResponse200.from_dict(response.json()) return response_200 if response.status_code == 404: response_404 = NotFound.from_dict(response.json()) @@ -784,14 +730,15 @@ def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Unio else: return None - def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) + def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) - async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике + async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. Args: id (int): @@ -801,17 +748,18 @@ async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmplo httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetEmployeeResponse200, NotFound]] + Response[Union[GetMessageResponse200, NotFound]] """ - kwargs = self._get_kwargs_getEmployee(id=id) + kwargs = self._get_kwargs_getMessage(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(response=response) + return self._build_response_getMessage(response=response) - async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике + async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. Args: id (int): @@ -821,264 +769,309 @@ async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, N httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetEmployeeResponse200, NotFound] + Union[GetMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_getEmployee(id=id)).parsed + return (await self.asyncio_detailed_getMessage(id=id)).parsed - def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: + def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} + params['chat_id'] = chat_id params['per'] = per params['page'] = page - params['query'] = query params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} return _kwargs - def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: + def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) + response_200 = GetListMessageResponse200.from_dict(response.json()) return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) + def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) - async def asyncio_detailed_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании + async def asyncio_detailed_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата - Fetch a paginated list of employees with optional filtering by query. + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. Args: - per (Union[Unset, int]): Default: 50. + chat_id (int): + per (Union[Unset, int]): Default: 25. page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[GetEmployeesResponse200] + Response[Union[BadRequest, GetListMessageResponse200, NotFound]] """ - kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) + kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(response=response) + return self._build_response_getListMessage(response=response) - async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании + async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата - Fetch a paginated list of employees with optional filtering by query. + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. Args: - per (Union[Unset, int]): Default: 50. + chat_id (int): + per (Union[Unset, int]): Default: 25. page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - GetEmployeesResponse200 + Union[BadRequest, GetListMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_getEmployees(per=per, page=page, query=query)).parsed + return (await self.asyncio_detailed_getListMessage(chat_id=chat_id, per=per, page=page)).parsed - def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: + def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} _body = body.to_dict() _kwargs['json'] = _body headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: if response.status_code == 201: - response_201 = CreateMessageResponse201.from_dict(response.json()) + response_201 = cast(Any, None) return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) + + async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['ErrorsCode']]] + """ + kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postTagsToChats(response=response) + + async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed + + def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} + return _kwargs + + def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 if response.status_code == 404: response_404 = [] _response_404 = response.json() - for componentsschemas_errors_item_data in _response_404: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - response_404.append(componentsschemas_errors_item) + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) + def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) - async def asyncio_detailed_createMessage(self, body: CreateMessageBody) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. + async def asyncio_detailed_delete_chats_id_leave(self, id: int) -> Response[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. + Метод для самостоятельного выхода из беседы или канала. Args: - body (CreateMessageBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_createMessage(body=body) + kwargs = self._get_kwargs_delete_chats_id_leave(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createMessage(response=response) + return self._build_response_delete_chats_id_leave(response=response) - async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. + async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. + Метод для самостоятельного выхода из беседы или канала. Args: - body (CreateMessageBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_createMessage(body=body)).parsed + return (await self.asyncio_detailed_delete_chats_id_leave(id=id)).parsed - def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['chat_id'] = chat_id - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} + def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetListMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 + def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) + def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) - async def asyncio_detailed_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + async def asyncio_detailed_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. + Метод для добавления пользователей в состав участников беседы или канала. Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. + id (int): Example: 533. + body (PostMembersToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + Response[Union[Any, list['ErrorsCode']]] """ - kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) + kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getListMessage(response=response) + return self._build_response_postMembersToChats(response=response) - async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. + Метод для добавления пользователей в состав участников беседы или канала. Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. + id (int): Example: 533. + body (PostMembersToChatsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetListMessageResponse200, NotFound] + Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_getListMessage(chat_id=chat_id, per=per, page=page)).parsed + return (await self.asyncio_detailed_postMembersToChats(id=id, body=body)).parsed - def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} + def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} return _kwargs - def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: + def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) + response_200 = GetChatResponse200.from_dict(response.json()) return response_200 if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) + response_404 = GetChatResponse404.from_dict(response.json()) return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) + def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) - async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. + async def asyncio_detailed_getChat(self, id: int) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. Args: id (int): @@ -1088,18 +1081,17 @@ async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessag httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetMessageResponse200, NotFound]] + Response[Union[GetChatResponse200, GetChatResponse404]] """ - kwargs = self._get_kwargs_getMessage(id=id) + kwargs = self._get_kwargs_getChat(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(response=response) + return self._build_response_getChat(response=response) - async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. + async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. Args: id (int): @@ -1109,447 +1101,436 @@ async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, Not httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetMessageResponse200, NotFound] + Union[GetChatResponse200, GetChatResponse404] """ - return (await self.asyncio_detailed_getMessage(id=id)).parsed + return (await self.asyncio_detailed_getChat(id=id)).parsed - def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: + def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} _body = body.to_dict() _kwargs['json'] = _body headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = PutMessagesIdResponse200.from_dict(response.json()) - return response_200 + def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + return response_201 if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) + response_400 = CreateChatResponse400.from_dict(response.json()) return response_400 if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) + response_404 = CreateChatResponse404.from_dict(response.json()) return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + return response_422 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) + def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) - async def asyncio_detailed_put_messages_id(self, id: int, body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения + async def asyncio_detailed_createChat(self, body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал - Метод для редактирования сообщения или комментария. + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ Args: - id (int): - body (PutMessagesIdBody): + body (CreateChatBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] - """ - kwargs = self._get_kwargs_put_messages_id(id=id, body=body) + Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + """ + kwargs = self._get_kwargs_createChat(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(response=response) + return self._build_response_createChat(response=response) - async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения + async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал - Метод для редактирования сообщения или комментария. + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ Args: - id (int): - body (PutMessagesIdBody): + body (CreateChatBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[PutMessagesIdResponse200, list['ErrorsCode']] - """ - return (await self.asyncio_detailed_put_messages_id(id=id, body=body)).parsed + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + return (await self.asyncio_detailed_createChat(body=body)).parsed - def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: + def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: params: dict[str, Any] = {} - params['code'] = code + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + params['sort[id]'] = json_sortid + params['per'] = per + params['page'] = page + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + params['availability'] = json_availability + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params['last_message_at_after'] = json_last_message_at_after + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params['last_message_at_before'] = json_last_message_at_before params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} return _kwargs - def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 + def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + return response_200 if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + response_400 = GetChatsResponse400.from_dict(response.json()) return response_400 if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + response_404 = GetChatsResponse404.from_dict(response.json()) return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + return response_422 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) + def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) - async def asyncio_detailed_deleteMessageReactions(self, id: int, code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции + async def asyncio_detailed_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. + Получения списка бесед и каналов по заданным параметрам. Args: - id (int): - code (str): + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] """ - kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) + kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(response=response) + return self._build_response_getChats(response=response) - async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции + async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. + Получения списка бесед и каналов по заданным параметрам. Args: - id (int): - code (str): + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] """ - return (await self.asyncio_detailed_deleteMessageReactions(id=id, code=code)).parsed + return (await self.asyncio_detailed_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed - def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getStatus(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} return _kwargs - def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + response_200 = GetStatusResponse200.from_dict(response.json()) return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) + def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) - async def asyncio_detailed_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. + async def asyncio_detailed_getStatus(self) -> Response[GetStatusResponse200]: + """получение информации о своем статусе - Args: - id (int): - body (GetMessageReactionsBody): + Параметры запроса отсутствуют Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + Response[GetStatusResponse200] """ - kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) + kwargs = self._get_kwargs_getStatus() response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(response=response) + return self._build_response_getStatus(response=response) - async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. + async def getStatus(self) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе - Args: - id (int): - body (GetMessageReactionsBody): + Параметры запроса отсутствуют Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] + GetStatusResponse200 """ - return (await self.asyncio_detailed_getMessageReactions(id=id, body=body)).parsed + return (await self.asyncio_detailed_getStatus()).parsed - def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: + def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} + _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} _body = body.to_dict() _kwargs['json'] = _body headers['Content-Type'] = 'application/json' _kwargs['headers'] = headers return _kwargs - def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 + def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + return response_201 if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + response_400 = BadRequest.from_dict(response.json()) return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) + def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) - async def asyncio_detailed_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции + async def asyncio_detailed_putStatus(self, body: QueryStatus) -> Response[Union[BadRequest, PutStatusResponse201]]: + """новый статус - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. + Создание нового статуса. Args: - id (int): - body (PostMessageReactionsBody): + body (QueryStatus): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + Response[Union[BadRequest, PutStatusResponse201]] """ - kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) + kwargs = self._get_kwargs_putStatus(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(response=response) + return self._build_response_putStatus(response=response) - async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции + async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. + Создание нового статуса. Args: - id (int): - body (PostMessageReactionsBody): + body (QueryStatus): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + Union[BadRequest, PutStatusResponse201] """ - return (await self.asyncio_detailed_postMessageReactions(id=id, body=body)).parsed + return (await self.asyncio_detailed_putStatus(body=body)).parsed - def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_delStatus(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} return _kwargs - def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - if response.status_code == 201: - response_201 = PostTasksResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = PostTasksResponse400.from_dict(response.json()) - return response_400 + def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) + def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) - async def asyncio_detailed_post_tasks(self, body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + async def asyncio_detailed_delStatus(self) -> Response[Any]: + """удаление своего статуса - Args: - body (PostTasksBody): + Параметры запроса отсутствуют Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PostTasksResponse201, PostTasksResponse400]] + Response[Any] """ - kwargs = self._get_kwargs_post_tasks(body=body) + kwargs = self._get_kwargs_delStatus() response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(response=response) + return self._build_response_delStatus(response=response) + + def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} + return _kwargs + + def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. + async def asyncio_detailed_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + Метод для получения актуального списка тегов сотрудников. Args: - body (PostTasksBody): + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[PostTasksResponse201, PostTasksResponse400] + Response[Union[GetTagsResponse200, GetTagsResponse400]] """ - return (await self.asyncio_detailed_post_tasks(body=body)).parsed - - def _get_kwargs_delStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} - return _kwargs - - def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) + kwargs = self._get_kwargs_getTags(per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTags(response=response) - async def asyncio_detailed_delStatus(self) -> Response[Any]: - """удаление своего статуса + async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников - Параметры запроса отсутствуют + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any] + Union[GetTagsResponse200, GetTagsResponse400] """ - kwargs = self._get_kwargs_delStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delStatus(response=response) + return (await self.asyncio_detailed_getTags(per=per, page=page)).parsed - def _get_kwargs_getStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} + def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} return _kwargs - def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: + def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: if response.status_code == 200: - response_200 = GetStatusResponse200.from_dict(response.json()) + response_200 = GetTagResponse200.from_dict(response.json()) return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) + def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) - async def asyncio_detailed_getStatus(self) -> Response[GetStatusResponse200]: - """получение информации о своем статусе + async def asyncio_detailed_getTag(self, id: int) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге Параметры запроса отсутствуют + Args: + id (int): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[GetStatusResponse200] + Response[Union[GetTagResponse200, GetTagResponse404]] """ - kwargs = self._get_kwargs_getStatus() + kwargs = self._get_kwargs_getTag(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getStatus(response=response) + return self._build_response_getTag(response=response) - async def getStatus(self) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе + async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге Параметры запроса отсутствуют + Args: + id (int): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - GetStatusResponse200 + Union[GetTagResponse200, GetTagResponse404] """ - return (await self.asyncio_detailed_getStatus()).parsed + return (await self.asyncio_detailed_getTag(id=id)).parsed - def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} return _kwargs - def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: - if response.status_code == 201: - response_201 = PutStatusResponse201.from_dict(response.json()) - return response_201 + def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + return response_200 if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 @@ -1558,173 +1539,207 @@ def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[ else: return None - def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) + def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - async def asyncio_detailed_putStatus(self, body: QueryStatus) -> Response[Union[BadRequest, PutStatusResponse201]]: - """новый статус + async def asyncio_detailed_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега - Создание нового статуса. + Метод для получения актуального списка сотрудников тега. Args: - body (QueryStatus): + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, PutStatusResponse201]] + Response[Union[BadRequest, GetTagsEmployeesResponse200]] """ - kwargs = self._get_kwargs_putStatus(body=body) + kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_putStatus(response=response) + return self._build_response_getTagsEmployees(response=response) - async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус + async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега - Создание нового статуса. + Метод для получения актуального списка сотрудников тега. Args: - body (QueryStatus): + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, PutStatusResponse201] + Union[BadRequest, GetTagsEmployeesResponse200] """ - return (await self.asyncio_detailed_putStatus(body=body)).parsed + return (await self.asyncio_detailed_getTagsEmployees(id=id, per=per, page=page)).parsed - def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} + def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - if response.status_code == 200: - response_200 = GetTagResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = GetTagResponse404.from_dict(response.json()) - return response_404 + def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + if response.status_code == 201: + response_201 = PostTasksResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = PostTasksResponse400.from_dict(response.json()) + return response_400 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) + def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) - async def asyncio_detailed_getTag(self, id: int) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге + async def asyncio_detailed_post_tasks(self, body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. - Параметры запроса отсутствуют + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. Args: - id (int): + body (PostTasksBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetTagResponse200, GetTagResponse404]] + Response[Union[PostTasksResponse201, PostTasksResponse400]] """ - kwargs = self._get_kwargs_getTag(id=id) + kwargs = self._get_kwargs_post_tasks(body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTag(response=response) + return self._build_response_post_tasks(response=response) - async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге + async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: + """Метод для создания нового напоминания. - Параметры запроса отсутствуют + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. Args: - id (int): + body (PostTasksBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetTagResponse200, GetTagResponse404] + Union[PostTasksResponse201, PostTasksResponse400] """ - return (await self.asyncio_detailed_getTag(id=id)).parsed + return (await self.asyncio_detailed_post_tasks(body=body)).parsed - def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} + def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - return response_200 + def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) + def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - async def asyncio_detailed_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников + async def asyncio_detailed_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции - Метод для получения актуального списка тегов сотрудников. + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. + id (int): + body (PostMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetTagsResponse200, GetTagsResponse400]] + Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] """ - kwargs = self._get_kwargs_getTags(per=per, page=page) + kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(response=response) + return self._build_response_postMessageReactions(response=response) - async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников + async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции - Метод для получения актуального списка тегов сотрудников. + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. + id (int): + body (PostMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[GetTagsResponse200, GetTagsResponse400] + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] """ - return (await self.asyncio_detailed_getTags(per=per, page=page)).parsed + return (await self.asyncio_detailed_postMessageReactions(id=id, body=body)).parsed - def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} + def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers return _kwargs - def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 if response.status_code == 400: response_400 = BadRequest.from_dict(response.json()) return response_400 @@ -1733,246 +1748,231 @@ def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional else: return None - def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) + def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) - async def asyncio_detailed_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега + async def asyncio_detailed_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. - Метод для получения актуального списка сотрудников тега. + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. Args: id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. + body (GetMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetTagsEmployeesResponse200]] + Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] """ - kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) + kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(response=response) + return self._build_response_getMessageReactions(response=response) - async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега + async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. - Метод для получения актуального списка сотрудников тега. + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. Args: id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. + body (GetMessageReactionsBody): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[BadRequest, GetTagsEmployeesResponse200] + Union[BadRequest, GetMessageReactionsResponse200, NotFound] """ - return (await self.asyncio_detailed_getTagsEmployees(id=id, per=per, page=page)).parsed + return (await self.asyncio_detailed_getMessageReactions(id=id, body=body)).parsed - def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} + def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['code'] = code + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} return _kwargs - def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = cast(Any, None) - return response_200 + def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) return response_400 if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) + def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) - async def asyncio_detailed_delete_chats_id_leave(self, id: int) -> Response[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала + async def asyncio_detailed_deleteMessageReactions(self, id: int, code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции - Метод для самостоятельного выхода из беседы или канала. + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. Args: id (int): + code (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] """ - kwargs = self._get_kwargs_delete_chats_id_leave(id=id) + kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(response=response) + return self._build_response_deleteMessageReactions(response=response) - async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала + async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции - Метод для самостоятельного выхода из беседы или канала. + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. Args: id (int): + code (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] """ - return (await self.asyncio_detailed_delete_chats_id_leave(id=id)).parsed + return (await self.asyncio_detailed_deleteMessageReactions(id=id, code=code)).parsed - def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params['query'] = query + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} return _kwargs - def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 + def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + return response_200 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) + def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) - async def asyncio_detailed_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников + async def asyncio_detailed_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании - Метод для добавления пользователей в состав участников беседы или канала. + Fetch a paginated list of employees with optional filtering by query. Args: - id (int): Example: 533. - body (PostMembersToChatsBody): + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[GetEmployeesResponse200] """ - kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) + kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(response=response) + return self._build_response_getEmployees(response=response) - async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников + async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании - Метод для добавления пользователей в состав участников беседы или канала. + Fetch a paginated list of employees with optional filtering by query. Args: - id (int): Example: 533. - body (PostMembersToChatsBody): + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + GetEmployeesResponse200 """ - return (await self.asyncio_detailed_postMembersToChats(id=id, body=body)).parsed + return (await self.asyncio_detailed_getEmployees(per=per, page=page, query=query)).parsed - def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers + def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} return _kwargs - def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 + def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 if self.client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) else: return None - def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) + def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) - async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала + async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике - Метод для добавления тегов в состав участников беседы или канала. + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. Args: - id (int): Example: 533. - body (PostTagsToChatsBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Response[Union[GetEmployeeResponse200, NotFound]] """ - kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) + kwargs = self._get_kwargs_getEmployee(id=id) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(response=response) + return self._build_response_getEmployee(response=response) - async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала + async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике - Метод для добавления тегов в состав участников беседы или канала. + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. Args: - id (int): Example: 533. - body (PostTagsToChatsBody): + id (int): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, list['ErrorsCode']] + Union[GetEmployeeResponse200, NotFound] """ - return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed + return (await self.asyncio_detailed_getEmployee(id=id)).parsed \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pyproject.toml b/pachca-api-open-api-3-0-client/pyproject.toml index 29f8de8..da5dcfa 100644 --- a/pachca-api-open-api-3-0-client/pyproject.toml +++ b/pachca-api-open-api-3-0-client/pyproject.toml @@ -12,8 +12,8 @@ include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] [tool.poetry.dependencies] python = "^3.9" -httpx = ">=0.20.0,<0.28.0" -attrs = ">=21.3.0" +httpx = ">=0.20.0,<0.29.0" +attrs = ">=22.2.0" python-dateutil = "^2.8.0" [build-system] From 65aea52ef54c3a57feddd2e9743ba5e733efda98 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Dec 2024 22:57:51 +0300 Subject: [PATCH 082/296] fixed change --- .../pachca_api_open_api_3_0_client/client.py | 97 +++++++++---------- pachca.py | 2 +- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py index d268cdf..58415da 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -1,70 +1,63 @@ -from .models.get_employees_response_200 import GetEmployeesResponse200 +import datetime +import ssl +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx +from attrs import define, evolve, field + +from . import errors from .models.bad_request import BadRequest -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from .models.create_chat_body import CreateChatBody +from .models.create_chat_response_201 import CreateChatResponse201 from .models.create_chat_response_400 import CreateChatResponse400 -from .models.get_chats_response_400 import GetChatsResponse400 -from .models.get_message_response_200 import GetMessageResponse200 -from .models.post_tags_to_chats_body import PostTagsToChatsBody -from .models.direct_response import DirectResponse +from .models.create_chat_response_404 import CreateChatResponse404 +from .models.create_chat_response_422 import CreateChatResponse422 from .models.create_message_body import CreateMessageBody -from .models.post_members_to_chats_body import PostMembersToChatsBody +from .models.create_message_response_201 import CreateMessageResponse201 +from .models.create_thread_response_200 import CreateThreadResponse200 from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from typing import Any -from .models.create_chat_response_404 import CreateChatResponse404 -from .models.create_chat_response_201 import CreateChatResponse201 +from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .models.direct_response import DirectResponse +from .models.error import Error +from .models.errors_code import ErrorsCode from .models.file_response import FileResponse from .models.get_chat_response_200 import GetChatResponse200 -from .models.get_chats_response_422 import GetChatsResponse422 +from .models.get_chat_response_404 import GetChatResponse404 +from .models.get_chats_availability import GetChatsAvailability +from .models.get_chats_response_200 import GetChatsResponse200 +from .models.get_chats_response_400 import GetChatsResponse400 from .models.get_chats_response_404 import GetChatsResponse404 -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .models.put_messages_id_body import PutMessagesIdBody +from .models.get_chats_response_422 import GetChatsResponse422 +from .models.get_chats_sortid import GetChatsSortid +from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 from .models.get_employee_response_200 import GetEmployeeResponse200 -from .models.error import Error -from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from .models.create_chat_response_422 import CreateChatResponse422 -from .types import UNSET -from .models.post_tasks_response_201 import PostTasksResponse201 -from http import HTTPStatus -from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.get_chat_response_404 import GetChatResponse404 +from .models.get_employees_response_200 import GetEmployeesResponse200 +from .models.get_list_message_response_200 import GetListMessageResponse200 +from .models.get_message_reactions_body import GetMessageReactionsBody +from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .models.get_message_response_200 import GetMessageResponse200 from .models.get_status_response_200 import GetStatusResponse200 -from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from . import errors -from .models.get_tag_response_404 import GetTagResponse404 -from .models.get_chats_sortid import GetChatsSortid -from .models.post_tasks_response_400 import PostTasksResponse400 -from .models.create_chat_body import CreateChatBody -from .models.get_chats_availability import GetChatsAvailability from .models.get_tag_response_200 import GetTagResponse200 -from .models.create_thread_response_200 import CreateThreadResponse200 +from .models.get_tag_response_404 import GetTagResponse404 from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from .models.get_list_message_response_200 import GetListMessageResponse200 -from .models.errors_code import ErrorsCode -from typing import Optional -from .models.put_status_response_201 import PutStatusResponse201 -from .models.not_found import NotFound -from .types import Unset -from typing import cast from .models.get_tags_response_200 import GetTagsResponse200 -from .models.query_status import QueryStatus -from .models.post_tasks_body import PostTasksBody -from .models.get_chats_response_200 import GetChatsResponse200 from .models.get_tags_response_400 import GetTagsResponse400 -from .types import Response -from typing import Union -from .models.create_message_response_201 import CreateMessageResponse201 +from .models.not_found import NotFound +from .models.post_members_to_chats_body import PostMembersToChatsBody +from .models.post_message_reactions_body import PostMessageReactionsBody from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .models.get_message_reactions_body import GetMessageReactionsBody from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 -from .models.post_message_reactions_body import PostMessageReactionsBody - -import datetime -import ssl -from typing import Any, Union, Optional - -from attrs import define, field, evolve -import httpx - +from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .models.post_tags_to_chats_body import PostTagsToChatsBody +from .models.post_tasks_body import PostTasksBody +from .models.post_tasks_response_201 import PostTasksResponse201 +from .models.post_tasks_response_400 import PostTasksResponse400 +from .models.put_messages_id_body import PutMessagesIdBody +from .models.put_messages_id_response_200 import PutMessagesIdResponse200 +from .models.put_status_response_201 import PutStatusResponse201 +from .models.query_status import QueryStatus +from .types import UNSET, Response, Unset @define diff --git a/pachca.py b/pachca.py index 6fad188..431f6b0 100644 --- a/pachca.py +++ b/pachca.py @@ -25,4 +25,4 @@ async def main(): if __name__ == '__main__': - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) From 5e540074165610689c6cfcd38dec964263bad4c8 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Dec 2024 23:01:24 +0300 Subject: [PATCH 083/296] remove intermediate func in endpoints --- .../api/chats_and_channels/create_chat.py | 35 +- .../api/chats_and_channels/get_chat.py | 35 +- .../api/chats_and_channels/get_chats.py | 50 +- .../api/comments/create_thread.py | 35 +- .../api/common_methods/get_common_methods.py | 35 +- .../api/common_methods/get_direct_url.py | 28 - .../api/common_methods/get_uploads.py | 26 +- .../api/employees/get_employee.py | 35 +- .../api/employees/get_employees.py | 40 +- .../api/messages/create_message.py | 46 +- .../api/messages/get_list_message.py | 45 +- .../api/messages/get_message.py | 36 +- .../api/messages/put_messages_id.py | 37 +- .../delete_message_reactions.py | 38 +- .../get_message_reactions.py | 38 +- .../post_message_reactions.py | 41 +- .../api/reminders/post_tasks.py | 39 +- .../api/status/del_status.py | 22 - .../api/status/get_status.py | 26 +- .../api/status/put_status.py | 34 +- .../api/tags/get_tag.py | 34 +- .../api/tags/get_tags.py | 37 +- .../api/tags/get_tags_employees.py | 40 +- .../delete_chats_id_leave.py | 34 +- .../post_members_to_chats.py | 37 +- .../post_tags_to_chats.py | 37 +- .../pachca_api_open_api_3_0_client/client.py | 734 +++--------------- templates/endpoint_module.py.jinja | 21 +- 28 files changed, 229 insertions(+), 1466 deletions(-) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py index aad296e..89cdc5a 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -68,10 +68,10 @@ def _build_response_createChat( ) -async def asyncio_detailed_createChat( +async def createChat( self, body: CreateChatBody, -) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: r""" Новая беседа или канал Метод для создания новой беседы или нового канала. @@ -85,7 +85,7 @@ async def asyncio_detailed_createChat( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] """ kwargs = self._get_kwargs_createChat( @@ -94,31 +94,4 @@ async def asyncio_detailed_createChat( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(response=response) - - -async def createChat( - self, - body: CreateChatBody, -) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - r""" Новая беседа или канал - - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ - - Args: - body (CreateChatBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - - return ( - await self.asyncio_detailed_createChat( - body=body, - ) - ).parsed + return self._build_response_createChat(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py index 88b08c1..e134dd6 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -45,10 +45,10 @@ def _build_response_getChat(self, response: httpx.Response) -> Response[Union[Ge ) -async def asyncio_detailed_getChat( +async def getChat( self, id: int, -) -> Response[Union[GetChatResponse200, GetChatResponse404]]: +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: """Информация о беседе или канале Получения информации о беседе или канале. @@ -62,7 +62,7 @@ async def asyncio_detailed_getChat( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatResponse200, GetChatResponse404]] + Union[GetChatResponse200, GetChatResponse404] """ kwargs = self._get_kwargs_getChat( @@ -71,31 +71,4 @@ async def asyncio_detailed_getChat( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(response=response) - - -async def getChat( - self, - id: int, -) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале - - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatResponse200, GetChatResponse404] - """ - - return ( - await self.asyncio_detailed_getChat( - id=id, - ) - ).parsed + return self._build_response_getChat(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py index 182e112..bebb456 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -98,7 +98,7 @@ def _build_response_getChats( ) -async def asyncio_detailed_getChats( +async def getChats( self, sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, per: Union[Unset, int] = 25, @@ -106,7 +106,7 @@ async def asyncio_detailed_getChats( availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime] = UNSET, last_message_at_before: Union[Unset, datetime.datetime] = UNSET, -) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: """Список бесед и каналов Получения списка бесед и каналов по заданным параметрам. @@ -125,7 +125,7 @@ async def asyncio_detailed_getChats( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] """ kwargs = self._get_kwargs_getChats( @@ -139,46 +139,4 @@ async def asyncio_detailed_getChats( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(response=response) - - -async def getChats( - self, - sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, - availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, - last_message_at_after: Union[Unset, datetime.datetime] = UNSET, - last_message_at_before: Union[Unset, datetime.datetime] = UNSET, -) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - - return ( - await self.asyncio_detailed_getChats( - sortid=sortid, - per=per, - page=page, - availability=availability, - last_message_at_after=last_message_at_after, - last_message_at_before=last_message_at_before, - ) - ).parsed + return self._build_response_getChats(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py index affccc4..eb23656 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -54,10 +54,10 @@ def _build_response_createThread( ) -async def asyncio_detailed_createThread( +async def createThread( self, id: int, -) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: """Создание нового треда Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в @@ -71,7 +71,7 @@ async def asyncio_detailed_createThread( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, CreateThreadResponse200, NotFound]] + Union[BadRequest, CreateThreadResponse200, NotFound] """ kwargs = self._get_kwargs_createThread( @@ -80,31 +80,4 @@ async def asyncio_detailed_createThread( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(response=response) - - -async def createThread( - self, - id: int, -) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - - return ( - await self.asyncio_detailed_createThread( - id=id, - ) - ).parsed + return self._build_response_createThread(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py index f26f8cc..7eeb703 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -56,10 +56,10 @@ def _build_response_getCommonMethods( ) -async def asyncio_detailed_getCommonMethods( +async def getCommonMethods( self, entity_type: str, -) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: """Список дополнительных полей Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей @@ -73,7 +73,7 @@ async def asyncio_detailed_getCommonMethods( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetCommonMethodsResponse200]] + Union[BadRequest, GetCommonMethodsResponse200] """ kwargs = self._get_kwargs_getCommonMethods( @@ -82,31 +82,4 @@ async def asyncio_detailed_getCommonMethods( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(response=response) - - -async def getCommonMethods( - self, - entity_type: str, -) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetCommonMethodsResponse200] - """ - - return ( - await self.asyncio_detailed_getCommonMethods( - entity_type=entity_type, - ) - ).parsed + return self._build_response_getCommonMethods(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py index 5124a72..49b24c6 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py @@ -43,31 +43,3 @@ def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response), ) - - -async def asyncio_detailed_getDirectUrl( - self, - body: DirectResponse, -) -> Response[Any]: - """Получение URL для загрузки - - Отправляет запрос для получения URL для безопасной загрузки файла. - - Args: - body (DirectResponse): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = self._get_kwargs_getDirectUrl( - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getDirectUrl(response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py index eb3f137..b5ddcd3 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -39,9 +39,9 @@ def _build_response_getUploads(self, response: httpx.Response) -> Response[FileR ) -async def asyncio_detailed_getUploads( +async def getUploads( self, -) -> Response[FileResponse]: +) -> Optional[FileResponse]: """Получение подписи и ключа для загрузки файла Возвращает параметры, необходимые для безопасной загрузки файла. @@ -51,29 +51,11 @@ async def asyncio_detailed_getUploads( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[FileResponse] + FileResponse """ kwargs = self._get_kwargs_getUploads() response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getUploads(response=response) - - -async def getUploads( - self, -) -> Optional[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - FileResponse - """ - - return (await self.asyncio_detailed_getUploads()).parsed + return self._build_response_getUploads(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py index 98327ba..5f758db 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -45,10 +45,10 @@ def _build_response_getEmployee(self, response: httpx.Response) -> Response[Unio ) -async def asyncio_detailed_getEmployee( +async def getEmployee( self, id: int, -) -> Response[Union[GetEmployeeResponse200, NotFound]]: +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: """получение информации о сотруднике Метод для получения информации о сотруднике. @@ -62,7 +62,7 @@ async def asyncio_detailed_getEmployee( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetEmployeeResponse200, NotFound]] + Union[GetEmployeeResponse200, NotFound] """ kwargs = self._get_kwargs_getEmployee( @@ -71,31 +71,4 @@ async def asyncio_detailed_getEmployee( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(response=response) - - -async def getEmployee( - self, - id: int, -) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetEmployeeResponse200, NotFound] - """ - - return ( - await self.asyncio_detailed_getEmployee( - id=id, - ) - ).parsed + return self._build_response_getEmployee(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py index efcbab5..d68f825 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -53,12 +53,12 @@ def _build_response_getEmployees(self, response: httpx.Response) -> Response[Get ) -async def asyncio_detailed_getEmployees( +async def getEmployees( self, per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, query: Union[Unset, str] = UNSET, -) -> Response[GetEmployeesResponse200]: +) -> Optional[GetEmployeesResponse200]: """получение актуального списка всех сотрудников компании Fetch a paginated list of employees with optional filtering by query. @@ -73,7 +73,7 @@ async def asyncio_detailed_getEmployees( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[GetEmployeesResponse200] + GetEmployeesResponse200 """ kwargs = self._get_kwargs_getEmployees( @@ -84,36 +84,4 @@ async def asyncio_detailed_getEmployees( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(response=response) - - -async def getEmployees( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, - query: Union[Unset, str] = UNSET, -) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetEmployeesResponse200 - """ - - return ( - await self.asyncio_detailed_getEmployees( - per=per, - page=page, - query=query, - ) - ).parsed + return self._build_response_getEmployees(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py index 48c4388..89fccb4 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -68,10 +68,10 @@ def _build_response_createMessage( ) -async def asyncio_detailed_createMessage( +async def createMessage( self, body: CreateMessageBody, -) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: r"""создание нового сообщения Метод для отправки сообщения в беседу или канал, @@ -96,7 +96,7 @@ async def asyncio_detailed_createMessage( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] + Union[BadRequest, CreateMessageResponse201, list['Error']] """ kwargs = self._get_kwargs_createMessage( @@ -105,42 +105,4 @@ async def asyncio_detailed_createMessage( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createMessage(response=response) - - -async def createMessage( - self, - body: CreateMessageBody, -) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - r"""создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \"discussion\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \"user\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - - Args: - body (CreateMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] - """ - - return ( - await self.asyncio_detailed_createMessage( - body=body, - ) - ).parsed + return self._build_response_createMessage(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py index 64487d6..090f093 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -67,12 +67,12 @@ def _build_response_getListMessage( ) -async def asyncio_detailed_getListMessage( +async def getListMessage( self, chat_id: int, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, -) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: """получение списка сообщений чата Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. @@ -92,7 +92,7 @@ async def asyncio_detailed_getListMessage( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetListMessageResponse200, NotFound]] + Union[BadRequest, GetListMessageResponse200, NotFound] """ kwargs = self._get_kwargs_getListMessage( @@ -103,41 +103,4 @@ async def asyncio_detailed_getListMessage( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getListMessage(response=response) - - -async def getListMessage( - self, - chat_id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - - Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetListMessageResponse200, NotFound] - """ - - return ( - await self.asyncio_detailed_getListMessage( - chat_id=chat_id, - per=per, - page=page, - ) - ).parsed + return self._build_response_getListMessage(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py index 6f2ec30..83f1f22 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -45,10 +45,10 @@ def _build_response_getMessage(self, response: httpx.Response) -> Response[Union ) -async def asyncio_detailed_getMessage( +async def getMessage( self, id: int, -) -> Response[Union[GetMessageResponse200, NotFound]]: +) -> Optional[Union[GetMessageResponse200, NotFound]]: """получение информации о сообщении Метод для получения информации о сообщении. @@ -63,7 +63,7 @@ async def asyncio_detailed_getMessage( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetMessageResponse200, NotFound]] + Union[GetMessageResponse200, NotFound] """ kwargs = self._get_kwargs_getMessage( @@ -72,32 +72,4 @@ async def asyncio_detailed_getMessage( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(response=response) - - -async def getMessage( - self, - id: int, -) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetMessageResponse200, NotFound] - """ - - return ( - await self.asyncio_detailed_getMessage( - id=id, - ) - ).parsed + return self._build_response_getMessage(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py index 0de0ea1..6593577 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py @@ -73,11 +73,11 @@ def _build_response_put_messages_id( ) -async def asyncio_detailed_put_messages_id( +async def put_messages_id( self, id: int, body: PutMessagesIdBody, -) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: +) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: """Редактирование сообщения Метод для редактирования сообщения или комментария. @@ -91,7 +91,7 @@ async def asyncio_detailed_put_messages_id( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] + Union[PutMessagesIdResponse200, list['ErrorsCode']] """ kwargs = self._get_kwargs_put_messages_id( @@ -101,33 +101,4 @@ async def asyncio_detailed_put_messages_id( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(response=response) - - -async def put_messages_id( - self, - id: int, - body: PutMessagesIdBody, -) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: - """Редактирование сообщения - - Метод для редактирования сообщения или комментария. - - Args: - id (int): - body (PutMessagesIdBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PutMessagesIdResponse200, list['ErrorsCode']] - """ - - return ( - await self.asyncio_detailed_put_messages_id( - id=id, - body=body, - ) - ).parsed + return self._build_response_put_messages_id(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py index 8b717d9..92090b4 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -60,11 +60,11 @@ def _build_response_deleteMessageReactions( ) -async def asyncio_detailed_deleteMessageReactions( +async def deleteMessageReactions( self, id: int, code: str, -) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: """Удаление реакции Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены @@ -79,7 +79,7 @@ async def asyncio_detailed_deleteMessageReactions( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] """ kwargs = self._get_kwargs_deleteMessageReactions( @@ -89,34 +89,4 @@ async def asyncio_detailed_deleteMessageReactions( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(response=response) - - -async def deleteMessageReactions( - self, - id: int, - code: str, -) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. - - Args: - id (int): - code (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] - """ - - return ( - await self.asyncio_detailed_deleteMessageReactions( - id=id, - code=code, - ) - ).parsed + return self._build_response_deleteMessageReactions(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py index 4e11ad7..e2721f1 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -64,11 +64,11 @@ def _build_response_getMessageReactions( ) -async def asyncio_detailed_getMessageReactions( +async def getMessageReactions( self, id: int, body: GetMessageReactionsBody, -) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: """Получение актуального списка реакций. Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное @@ -83,7 +83,7 @@ async def asyncio_detailed_getMessageReactions( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] + Union[BadRequest, GetMessageReactionsResponse200, NotFound] """ kwargs = self._get_kwargs_getMessageReactions( @@ -93,34 +93,4 @@ async def asyncio_detailed_getMessageReactions( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(response=response) - - -async def getMessageReactions( - self, - id: int, - body: GetMessageReactionsBody, -) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. - - Args: - id (int): - body (GetMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] - """ - - return ( - await self.asyncio_detailed_getMessageReactions( - id=id, - body=body, - ) - ).parsed + return self._build_response_getMessageReactions(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py index fb88d7d..7386098 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -71,11 +71,11 @@ def _build_response_postMessageReactions( ) -async def asyncio_detailed_postMessageReactions( +async def postMessageReactions( self, id: int, body: PostMessageReactionsBody, -) -> Response[ +) -> Optional[ Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] ]: """Добавление реакции @@ -93,7 +93,7 @@ async def asyncio_detailed_postMessageReactions( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] """ kwargs = self._get_kwargs_postMessageReactions( @@ -103,37 +103,4 @@ async def asyncio_detailed_postMessageReactions( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(response=response) - - -async def postMessageReactions( - self, - id: int, - body: PostMessageReactionsBody, -) -> Optional[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (int): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] - """ - - return ( - await self.asyncio_detailed_postMessageReactions( - id=id, - body=body, - ) - ).parsed + return self._build_response_postMessageReactions(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py index b689520..a149f83 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py @@ -58,10 +58,10 @@ def _build_response_post_tasks( ) -async def asyncio_detailed_post_tasks( +async def post_tasks( self, body: PostTasksBody, -) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: +) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: """Метод для создания нового напоминания. При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, @@ -79,7 +79,7 @@ async def asyncio_detailed_post_tasks( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[PostTasksResponse201, PostTasksResponse400]] + Union[PostTasksResponse201, PostTasksResponse400] """ kwargs = self._get_kwargs_post_tasks( @@ -88,35 +88,4 @@ async def asyncio_detailed_post_tasks( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(response=response) - - -async def post_tasks( - self, - body: PostTasksBody, -) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (PostTasksBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PostTasksResponse201, PostTasksResponse400] - """ - - return ( - await self.asyncio_detailed_post_tasks( - body=body, - ) - ).parsed + return self._build_response_post_tasks(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py index 4c89a88..343eec6 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py @@ -34,25 +34,3 @@ def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: headers=response.headers, parsed=self._parse_response_delStatus(response=response), ) - - -async def asyncio_detailed_delStatus( - self, -) -> Response[Any]: - """удаление своего статуса - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = self._get_kwargs_delStatus() - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_delStatus(response=response) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py index 2440e05..f0ebcd7 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -39,9 +39,9 @@ def _build_response_getStatus(self, response: httpx.Response) -> Response[GetSta ) -async def asyncio_detailed_getStatus( +async def getStatus( self, -) -> Response[GetStatusResponse200]: +) -> Optional[GetStatusResponse200]: """получение информации о своем статусе Параметры запроса отсутствуют @@ -51,29 +51,11 @@ async def asyncio_detailed_getStatus( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[GetStatusResponse200] + GetStatusResponse200 """ kwargs = self._get_kwargs_getStatus() response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getStatus(response=response) - - -async def getStatus( - self, -) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetStatusResponse200 - """ - - return (await self.asyncio_detailed_getStatus()).parsed + return self._build_response_getStatus(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py index e085477..1211045 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -54,10 +54,10 @@ def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[ ) -async def asyncio_detailed_putStatus( +async def putStatus( self, body: QueryStatus, -) -> Response[Union[BadRequest, PutStatusResponse201]]: +) -> Optional[Union[BadRequest, PutStatusResponse201]]: """новый статус Создание нового статуса. @@ -70,7 +70,7 @@ async def asyncio_detailed_putStatus( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, PutStatusResponse201]] + Union[BadRequest, PutStatusResponse201] """ kwargs = self._get_kwargs_putStatus( @@ -79,30 +79,4 @@ async def asyncio_detailed_putStatus( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_putStatus(response=response) - - -async def putStatus( - self, - body: QueryStatus, -) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус - - Создание нового статуса. - - Args: - body (QueryStatus): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, PutStatusResponse201] - """ - - return ( - await self.asyncio_detailed_putStatus( - body=body, - ) - ).parsed + return self._build_response_putStatus(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py index ac9ad1d..4f0b49f 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -45,10 +45,10 @@ def _build_response_getTag(self, response: httpx.Response) -> Response[Union[Get ) -async def asyncio_detailed_getTag( +async def getTag( self, id: int, -) -> Response[Union[GetTagResponse200, GetTagResponse404]]: +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: """Информация о теге Параметры запроса отсутствуют @@ -61,7 +61,7 @@ async def asyncio_detailed_getTag( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetTagResponse200, GetTagResponse404]] + Union[GetTagResponse200, GetTagResponse404] """ kwargs = self._get_kwargs_getTag( @@ -70,30 +70,4 @@ async def asyncio_detailed_getTag( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTag(response=response) - - -async def getTag( - self, - id: int, -) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге - - Параметры запроса отсутствуют - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagResponse200, GetTagResponse404] - """ - - return ( - await self.asyncio_detailed_getTag( - id=id, - ) - ).parsed + return self._build_response_getTag(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py index c3909bb..9710704 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -55,11 +55,11 @@ def _build_response_getTags(self, response: httpx.Response) -> Response[Union[Ge ) -async def asyncio_detailed_getTags( +async def getTags( self, per: Union[Unset, int] = 50, page: Union[Unset, int] = 1, -) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: """Список тегов сотрудников Метод для получения актуального списка тегов сотрудников. @@ -73,7 +73,7 @@ async def asyncio_detailed_getTags( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[GetTagsResponse200, GetTagsResponse400]] + Union[GetTagsResponse200, GetTagsResponse400] """ kwargs = self._get_kwargs_getTags( @@ -83,33 +83,4 @@ async def asyncio_detailed_getTags( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(response=response) - - -async def getTags( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, -) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagsResponse200, GetTagsResponse400] - """ - - return ( - await self.asyncio_detailed_getTags( - per=per, - page=page, - ) - ).parsed + return self._build_response_getTags(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py index eb690ae..d259ecd 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -60,12 +60,12 @@ def _build_response_getTagsEmployees( ) -async def asyncio_detailed_getTagsEmployees( +async def getTagsEmployees( self, id: int, per: Union[Unset, int] = 25, page: Union[Unset, int] = 1, -) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: """получение актуального списка сотрудников тега Метод для получения актуального списка сотрудников тега. @@ -80,7 +80,7 @@ async def asyncio_detailed_getTagsEmployees( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[BadRequest, GetTagsEmployeesResponse200]] + Union[BadRequest, GetTagsEmployeesResponse200] """ kwargs = self._get_kwargs_getTagsEmployees( @@ -91,36 +91,4 @@ async def asyncio_detailed_getTagsEmployees( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(response=response) - - -async def getTagsEmployees( - self, - id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetTagsEmployeesResponse200] - """ - - return ( - await self.asyncio_detailed_getTagsEmployees( - id=id, - per=per, - page=page, - ) - ).parsed + return self._build_response_getTagsEmployees(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py index ea2661f..cac771d 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py @@ -57,10 +57,10 @@ def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Res ) -async def asyncio_detailed_delete_chats_id_leave( +async def delete_chats_id_leave( self, id: int, -) -> Response[Union[Any, list["ErrorsCode"]]]: +) -> Optional[Union[Any, list["ErrorsCode"]]]: """Выход из беседы или канала Метод для самостоятельного выхода из беседы или канала. @@ -73,7 +73,7 @@ async def asyncio_detailed_delete_chats_id_leave( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_delete_chats_id_leave( @@ -82,30 +82,4 @@ async def asyncio_detailed_delete_chats_id_leave( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(response=response) - - -async def delete_chats_id_leave( - self, - id: int, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """Выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - return ( - await self.asyncio_detailed_delete_chats_id_leave( - id=id, - ) - ).parsed + return self._build_response_delete_chats_id_leave(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py index 81b5bd6..5710447 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -58,11 +58,11 @@ def _build_response_postMembersToChats(self, response: httpx.Response) -> Respon ) -async def asyncio_detailed_postMembersToChats( +async def postMembersToChats( self, id: int, body: PostMembersToChatsBody, -) -> Response[Union[Any, list["ErrorsCode"]]]: +) -> Optional[Union[Any, list["ErrorsCode"]]]: """добавление пользователей в состав участников Метод для добавления пользователей в состав участников беседы или канала. @@ -76,7 +76,7 @@ async def asyncio_detailed_postMembersToChats( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_postMembersToChats( @@ -86,33 +86,4 @@ async def asyncio_detailed_postMembersToChats( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(response=response) - - -async def postMembersToChats( - self, - id: int, - body: PostMembersToChatsBody, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostMembersToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - return ( - await self.asyncio_detailed_postMembersToChats( - id=id, - body=body, - ) - ).parsed + return self._build_response_postMembersToChats(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py index f6c445c..1d90b2c 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -58,11 +58,11 @@ def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[ ) -async def asyncio_detailed_postTagsToChats( +async def postTagsToChats( self, id: int, body: PostTagsToChatsBody, -) -> Response[Union[Any, list["ErrorsCode"]]]: +) -> Optional[Union[Any, list["ErrorsCode"]]]: """добавление тегов в состав участников беседы или канала Метод для добавления тегов в состав участников беседы или канала. @@ -76,7 +76,7 @@ async def asyncio_detailed_postTagsToChats( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_postTagsToChats( @@ -86,33 +86,4 @@ async def asyncio_detailed_postTagsToChats( response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(response=response) - - -async def postTagsToChats( - self, - id: int, - body: PostTagsToChatsBody, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostTagsToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - return ( - await self.asyncio_detailed_postTagsToChats( - id=id, - body=body, - ) - ).parsed + return self._build_response_postTagsToChats(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py index 58415da..961bce4 100644 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py @@ -1,63 +1,70 @@ -import datetime -import ssl -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx -from attrs import define, evolve, field - -from . import errors -from .models.bad_request import BadRequest -from .models.create_chat_body import CreateChatBody -from .models.create_chat_response_201 import CreateChatResponse201 -from .models.create_chat_response_400 import CreateChatResponse400 +from .models.get_employee_response_200 import GetEmployeeResponse200 +from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from .models.get_message_response_200 import GetMessageResponse200 +from .models.get_chats_response_200 import GetChatsResponse200 +from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 from .models.create_chat_response_404 import CreateChatResponse404 +from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .models.get_list_message_response_200 import GetListMessageResponse200 +from .models.get_chats_response_400 import GetChatsResponse400 +from typing import Optional +from .models.post_message_reactions_body import PostMessageReactionsBody +from .types import UNSET +from .models.post_tasks_response_201 import PostTasksResponse201 +from .models.get_chat_response_200 import GetChatResponse200 +from typing import cast +from .models.get_chats_availability import GetChatsAvailability +from .models.get_status_response_200 import GetStatusResponse200 from .models.create_chat_response_422 import CreateChatResponse422 +from .models.not_found import NotFound from .models.create_message_body import CreateMessageBody +from .types import Response +from .models.direct_response import DirectResponse +from .models.get_chat_response_404 import GetChatResponse404 from .models.create_message_response_201 import CreateMessageResponse201 from .models.create_thread_response_200 import CreateThreadResponse200 -from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from .models.create_chat_body import CreateChatBody +from .models.query_status import QueryStatus +from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from typing import Any +from .models.create_chat_response_201 import CreateChatResponse201 +from .models.get_tag_response_200 import GetTagResponse200 +from .models.get_message_reactions_body import GetMessageReactionsBody +from .models.get_employees_response_200 import GetEmployeesResponse200 from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.direct_response import DirectResponse -from .models.error import Error -from .models.errors_code import ErrorsCode +from .models.bad_request import BadRequest from .models.file_response import FileResponse -from .models.get_chat_response_200 import GetChatResponse200 -from .models.get_chat_response_404 import GetChatResponse404 -from .models.get_chats_availability import GetChatsAvailability -from .models.get_chats_response_200 import GetChatsResponse200 -from .models.get_chats_response_400 import GetChatsResponse400 -from .models.get_chats_response_404 import GetChatsResponse404 -from .models.get_chats_response_422 import GetChatsResponse422 -from .models.get_chats_sortid import GetChatsSortid -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from .models.get_employee_response_200 import GetEmployeeResponse200 -from .models.get_employees_response_200 import GetEmployeesResponse200 -from .models.get_list_message_response_200 import GetListMessageResponse200 -from .models.get_message_reactions_body import GetMessageReactionsBody -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .models.get_message_response_200 import GetMessageResponse200 -from .models.get_status_response_200 import GetStatusResponse200 -from .models.get_tag_response_200 import GetTagResponse200 from .models.get_tag_response_404 import GetTagResponse404 -from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from http import HTTPStatus +from .models.get_chats_response_422 import GetChatsResponse422 from .models.get_tags_response_200 import GetTagsResponse200 +from . import errors +from typing import Union +from .types import Unset +from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .models.error import Error +from .models.get_chats_sortid import GetChatsSortid +from .models.get_chats_response_404 import GetChatsResponse404 +from .models.put_messages_id_body import PutMessagesIdBody +from .models.put_status_response_201 import PutStatusResponse201 +from .models.errors_code import ErrorsCode +from .models.create_chat_response_400 import CreateChatResponse400 +from .models.post_tasks_body import PostTasksBody from .models.get_tags_response_400 import GetTagsResponse400 -from .models.not_found import NotFound from .models.post_members_to_chats_body import PostMembersToChatsBody -from .models.post_message_reactions_body import PostMessageReactionsBody -from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 -from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from .models.post_tags_to_chats_body import PostTagsToChatsBody -from .models.post_tasks_body import PostTasksBody -from .models.post_tasks_response_201 import PostTasksResponse201 +from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 from .models.post_tasks_response_400 import PostTasksResponse400 -from .models.put_messages_id_body import PutMessagesIdBody +from .models.post_tags_to_chats_body import PostTagsToChatsBody from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from .models.put_status_response_201 import PutStatusResponse201 -from .models.query_status import QueryStatus -from .types import UNSET, Response, Unset +from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 + +import datetime +import ssl +from typing import Any, Union, Optional + +from attrs import define, field, evolve +import httpx + @define @@ -361,26 +368,6 @@ def _parse_response_createThread(self, response: httpx.Response) -> Optional[Uni def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) - async def asyncio_detailed_createThread(self, id: int) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, CreateThreadResponse200, NotFound]] - """ - kwargs = self._get_kwargs_createThread(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(response=response) - async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: """Создание нового треда @@ -397,7 +384,9 @@ async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThread Returns: Union[BadRequest, CreateThreadResponse200, NotFound] """ - return (await self.asyncio_detailed_createThread(id=id)).parsed + kwargs = self._get_kwargs_createThread(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createThread(response=response).parsed def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: params: dict[str, Any] = {} @@ -421,26 +410,6 @@ def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) - async def asyncio_detailed_getCommonMethods(self, entity_type: str) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, GetCommonMethodsResponse200]] - """ - kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(response=response) - async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: """Список дополнительных полей @@ -457,7 +426,9 @@ async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, Returns: Union[BadRequest, GetCommonMethodsResponse200] """ - return (await self.asyncio_detailed_getCommonMethods(entity_type=entity_type)).parsed + kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getCommonMethods(response=response).parsed def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -478,25 +449,6 @@ def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) - async def asyncio_detailed_getDirectUrl(self, body: DirectResponse) -> Response[Any]: - """Получение URL для загрузки - - Отправляет запрос для получения URL для безопасной загрузки файла. - - Args: - body (DirectResponse): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - kwargs = self._get_kwargs_getDirectUrl(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getDirectUrl(response=response) - def _get_kwargs_getUploads(self) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} return _kwargs @@ -513,22 +465,6 @@ def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileR def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) - async def asyncio_detailed_getUploads(self) -> Response[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[FileResponse] - """ - kwargs = self._get_kwargs_getUploads() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getUploads(response=response) - async def getUploads(self) -> Optional[FileResponse]: """Получение подписи и ключа для загрузки файла @@ -541,7 +477,9 @@ async def getUploads(self) -> Optional[FileResponse]: Returns: FileResponse """ - return (await self.asyncio_detailed_getUploads()).parsed + kwargs = self._get_kwargs_getUploads() + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getUploads(response=response).parsed def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -578,26 +516,6 @@ def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[ def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) - async def asyncio_detailed_put_messages_id(self, id: int, body: PutMessagesIdBody) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения - - Метод для редактирования сообщения или комментария. - - Args: - id (int): - body (PutMessagesIdBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]] - """ - kwargs = self._get_kwargs_put_messages_id(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(response=response) - async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: """Редактирование сообщения @@ -614,7 +532,9 @@ async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Un Returns: Union[PutMessagesIdResponse200, list['ErrorsCode']] """ - return (await self.asyncio_detailed_put_messages_id(id=id, body=body)).parsed + kwargs = self._get_kwargs_put_messages_id(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_put_messages_id(response=response).parsed def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -647,37 +567,6 @@ def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Un def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) - async def asyncio_detailed_createMessage(self, body: CreateMessageBody) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - - Args: - body (CreateMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, CreateMessageResponse201, list['Error']]] - """ - kwargs = self._get_kwargs_createMessage(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createMessage(response=response) - async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: """создание нового сообщения @@ -705,7 +594,9 @@ async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequ Returns: Union[BadRequest, CreateMessageResponse201, list['Error']] """ - return (await self.asyncio_detailed_createMessage(body=body)).parsed + kwargs = self._get_kwargs_createMessage(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createMessage(response=response).parsed def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} @@ -726,27 +617,6 @@ def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) - async def asyncio_detailed_getMessage(self, id: int) -> Response[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetMessageResponse200, NotFound]] - """ - kwargs = self._get_kwargs_getMessage(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(response=response) - async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: """получение информации о сообщении @@ -764,7 +634,9 @@ async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, Not Returns: Union[GetMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_getMessage(id=id)).parsed + kwargs = self._get_kwargs_getMessage(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getMessage(response=response).parsed def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} @@ -793,32 +665,6 @@ def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[U def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) - async def asyncio_detailed_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - - Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, GetListMessageResponse200, NotFound]] - """ - kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getListMessage(response=response) - async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: """получение списка сообщений чата @@ -841,7 +687,9 @@ async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Un Returns: Union[BadRequest, GetListMessageResponse200, NotFound] """ - return (await self.asyncio_detailed_getListMessage(chat_id=chat_id, per=per, page=page)).parsed + kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getListMessage(response=response).parsed def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -871,7 +719,7 @@ def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[ def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) - async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: + async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: """добавление тегов в состав участников беседы или канала Метод для добавления тегов в состав участников беседы или канала. @@ -885,29 +733,11 @@ async def asyncio_detailed_postTagsToChats(self, id: int, body: PostTagsToChatsB httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, list['ErrorsCode']]] + Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(response=response) - - async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostTagsToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - return (await self.asyncio_detailed_postTagsToChats(id=id, body=body)).parsed + return self._build_response_postTagsToChats(response=response).parsed def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} @@ -939,25 +769,6 @@ def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Opt def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) - async def asyncio_detailed_delete_chats_id_leave(self, id: int) -> Response[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, list['ErrorsCode']]] - """ - kwargs = self._get_kwargs_delete_chats_id_leave(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(response=response) - async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: """Выход из беседы или канала @@ -973,7 +784,9 @@ async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['Erro Returns: Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_delete_chats_id_leave(id=id)).parsed + kwargs = self._get_kwargs_delete_chats_id_leave(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_delete_chats_id_leave(response=response).parsed def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -1003,26 +816,6 @@ def _parse_response_postMembersToChats(self, response: httpx.Response) -> Option def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) - async def asyncio_detailed_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Response[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostMembersToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, list['ErrorsCode']]] - """ - kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(response=response) - async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: """добавление пользователей в состав участников @@ -1039,7 +832,9 @@ async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Opt Returns: Union[Any, list['ErrorsCode']] """ - return (await self.asyncio_detailed_postMembersToChats(id=id, body=body)).parsed + kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postMembersToChats(response=response).parsed def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} @@ -1060,26 +855,6 @@ def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[Ge def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) - async def asyncio_detailed_getChat(self, id: int) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале - - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetChatResponse200, GetChatResponse404]] - """ - kwargs = self._get_kwargs_getChat(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(response=response) - async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: """Информация о беседе или канале @@ -1096,7 +871,9 @@ async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatRe Returns: Union[GetChatResponse200, GetChatResponse404] """ - return (await self.asyncio_detailed_getChat(id=id)).parsed + kwargs = self._get_kwargs_getChat(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChat(response=response).parsed def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -1128,26 +905,6 @@ def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) - async def asyncio_detailed_createChat(self, body: CreateChatBody) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал - - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ - - Args: - body (CreateChatBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]] - """ - kwargs = self._get_kwargs_createChat(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(response=response) - async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: """ Новая беседа или канал @@ -1164,7 +921,9 @@ async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatRes Returns: Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] """ - return (await self.asyncio_detailed_createChat(body=body)).parsed + kwargs = self._get_kwargs_createChat(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createChat(response=response).parsed def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: params: dict[str, Any] = {} @@ -1211,31 +970,6 @@ def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[G def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) - async def asyncio_detailed_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]] - """ - kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(response=response) - async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: """Список бесед и каналов @@ -1257,7 +991,9 @@ async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DES Returns: Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] """ - return (await self.asyncio_detailed_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before)).parsed + kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChats(response=response).parsed def _get_kwargs_getStatus(self) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} @@ -1275,22 +1011,6 @@ def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetSta def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) - async def asyncio_detailed_getStatus(self) -> Response[GetStatusResponse200]: - """получение информации о своем статусе - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[GetStatusResponse200] - """ - kwargs = self._get_kwargs_getStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getStatus(response=response) - async def getStatus(self) -> Optional[GetStatusResponse200]: """получение информации о своем статусе @@ -1303,7 +1023,9 @@ async def getStatus(self) -> Optional[GetStatusResponse200]: Returns: GetStatusResponse200 """ - return (await self.asyncio_detailed_getStatus()).parsed + kwargs = self._get_kwargs_getStatus() + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getStatus(response=response).parsed def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -1329,25 +1051,6 @@ def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[ def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) - async def asyncio_detailed_putStatus(self, body: QueryStatus) -> Response[Union[BadRequest, PutStatusResponse201]]: - """новый статус - - Создание нового статуса. - - Args: - body (QueryStatus): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, PutStatusResponse201]] - """ - kwargs = self._get_kwargs_putStatus(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_putStatus(response=response) - async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: """новый статус @@ -1363,7 +1066,9 @@ async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutSt Returns: Union[BadRequest, PutStatusResponse201] """ - return (await self.asyncio_detailed_putStatus(body=body)).parsed + kwargs = self._get_kwargs_putStatus(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_putStatus(response=response).parsed def _get_kwargs_delStatus(self) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} @@ -1380,22 +1085,6 @@ def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) - async def asyncio_detailed_delStatus(self) -> Response[Any]: - """удаление своего статуса - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - kwargs = self._get_kwargs_delStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delStatus(response=response) - def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} params['per'] = per @@ -1419,26 +1108,6 @@ def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[Ge def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - async def asyncio_detailed_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetTagsResponse200, GetTagsResponse400]] - """ - kwargs = self._get_kwargs_getTags(per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(response=response) - async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: """Список тегов сотрудников @@ -1455,7 +1124,9 @@ async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Returns: Union[GetTagsResponse200, GetTagsResponse400] """ - return (await self.asyncio_detailed_getTags(per=per, page=page)).parsed + kwargs = self._get_kwargs_getTags(per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTags(response=response).parsed def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} @@ -1476,25 +1147,6 @@ def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[Get def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) - async def asyncio_detailed_getTag(self, id: int) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге - - Параметры запроса отсутствуют - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetTagResponse200, GetTagResponse404]] - """ - kwargs = self._get_kwargs_getTag(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTag(response=response) - async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: """Информация о теге @@ -1510,7 +1162,9 @@ async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagRespo Returns: Union[GetTagResponse200, GetTagResponse404] """ - return (await self.asyncio_detailed_getTag(id=id)).parsed + kwargs = self._get_kwargs_getTag(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTag(response=response).parsed def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: params: dict[str, Any] = {} @@ -1535,27 +1189,6 @@ def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - async def asyncio_detailed_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, GetTagsEmployeesResponse200]] - """ - kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(response=response) - async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: """получение актуального списка сотрудников тега @@ -1573,7 +1206,9 @@ async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union Returns: Union[BadRequest, GetTagsEmployeesResponse200] """ - return (await self.asyncio_detailed_getTagsEmployees(id=id, per=per, page=page)).parsed + kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTagsEmployees(response=response).parsed def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -1599,30 +1234,6 @@ def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) - async def asyncio_detailed_post_tasks(self, body: PostTasksBody) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (PostTasksBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[PostTasksResponse201, PostTasksResponse400]] - """ - kwargs = self._get_kwargs_post_tasks(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(response=response) - async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: """Метод для создания нового напоминания. @@ -1643,7 +1254,9 @@ async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksRespo Returns: Union[PostTasksResponse201, PostTasksResponse400] """ - return (await self.asyncio_detailed_post_tasks(body=body)).parsed + kwargs = self._get_kwargs_post_tasks(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_post_tasks(response=response).parsed def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -1675,28 +1288,6 @@ def _parse_response_postMessageReactions(self, response: httpx.Response) -> Opti def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - async def asyncio_detailed_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (int): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]] - """ - kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(response=response) - async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: """Добавление реакции @@ -1715,7 +1306,9 @@ async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Returns: Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] """ - return (await self.asyncio_detailed_postMessageReactions(id=id, body=body)).parsed + kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postMessageReactions(response=response).parsed def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: headers: dict[str, Any] = {} @@ -1744,27 +1337,6 @@ def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optio def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) - async def asyncio_detailed_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. - - Args: - id (int): - body (GetMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]] - """ - kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(response=response) - async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: """Получение актуального списка реакций. @@ -1782,7 +1354,9 @@ async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> O Returns: Union[BadRequest, GetMessageReactionsResponse200, NotFound] """ - return (await self.asyncio_detailed_getMessageReactions(id=id, body=body)).parsed + kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getMessageReactions(response=response).parsed def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: params: dict[str, Any] = {} @@ -1809,27 +1383,6 @@ def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Op def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) - async def asyncio_detailed_deleteMessageReactions(self, id: int, code: str) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. - - Args: - id (int): - code (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]] - """ - kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(response=response) - async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: """Удаление реакции @@ -1847,7 +1400,9 @@ async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any Returns: Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] """ - return (await self.asyncio_detailed_deleteMessageReactions(id=id, code=code)).parsed + kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_deleteMessageReactions(response=response).parsed def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: params: dict[str, Any] = {} @@ -1870,27 +1425,6 @@ def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[Get def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) - async def asyncio_detailed_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Response[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[GetEmployeesResponse200] - """ - kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(response=response) - async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: """получение актуального списка всех сотрудников компании @@ -1908,7 +1442,9 @@ async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]= Returns: GetEmployeesResponse200 """ - return (await self.asyncio_detailed_getEmployees(per=per, page=page, query=query)).parsed + kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployees(response=response).parsed def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} @@ -1929,26 +1465,6 @@ def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Unio def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) - async def asyncio_detailed_getEmployee(self, id: int) -> Response[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[GetEmployeeResponse200, NotFound]] - """ - kwargs = self._get_kwargs_getEmployee(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(response=response) - async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: """получение информации о сотруднике @@ -1965,7 +1481,9 @@ async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, N Returns: Union[GetEmployeeResponse200, NotFound] """ - return (await self.asyncio_detailed_getEmployee(id=id)).parsed + kwargs = self._get_kwargs_getEmployee(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployee(response=response).parsed \ No newline at end of file diff --git a/templates/endpoint_module.py.jinja b/templates/endpoint_module.py.jinja index e04e9c0..81a1c3c 100644 --- a/templates/endpoint_module.py.jinja +++ b/templates/endpoint_module.py.jinja @@ -98,10 +98,12 @@ def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> Respo parsed=self._parse_response_{{ endpoint.name }}(response=response), ) -async def asyncio_detailed_{{ endpoint.name }}(self, + +{% if parsed_responses %} +async def {{ endpoint.name }}(self, {{ arguments(endpoint) | indent(4) }} -) -> Response[{{ return_string }}]: - {{ docstring(endpoint, return_string, is_detailed=true) | indent(4) }} +) -> Optional[{{ return_string }}]: + {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} kwargs = self._get_kwargs_{{ endpoint.name }}( {{ kwargs(endpoint, include_client=False) }} @@ -111,16 +113,7 @@ async def asyncio_detailed_{{ endpoint.name }}(self, **kwargs ) - return self._build_response_{{ endpoint.name }}(response=response) - -{% if parsed_responses %} -async def {{ endpoint.name }}(self, - {{ arguments(endpoint) | indent(4) }} -) -> Optional[{{ return_string }}]: - {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} - - return (await self.asyncio_detailed_{{ endpoint.name }}( - {{ kwargs(endpoint) }} - )).parsed + return self._build_response_{{ endpoint.name }}( + response=response).parsed {% endif %} From 1e8bf515de7e64827298eb4ca94b9d0daba6e87f Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Dec 2024 23:03:45 +0300 Subject: [PATCH 084/296] change gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9374355..94ae0ac 100644 --- a/.gitignore +++ b/.gitignore @@ -163,3 +163,6 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ .vscode/ + + +pachca-api-open-api-3-0-client/ \ No newline at end of file From bfc74e670e7fed111dd74843516955715dd689d6 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Dec 2024 23:31:56 +0300 Subject: [PATCH 085/296] project structure refactoring --- .gitignore | 1 - pachca-api-open-api-3-0-client/.gitignore | 23 - pachca-api-open-api-3-0-client/README.md | 124 -- .../__init__.py | 8 - .../api/__init__.py | 1 - .../api/chats_and_channels/__init__.py | 0 .../api/chats_and_channels/create_chat.py | 97 -- .../api/chats_and_channels/get_chat.py | 74 - .../api/chats_and_channels/get_chats.py | 142 -- .../api/comments/__init__.py | 0 .../api/comments/create_thread.py | 83 - .../api/common_methods/__init__.py | 0 .../api/common_methods/get_common_methods.py | 85 - .../api/common_methods/get_direct_url.py | 45 - .../api/common_methods/get_uploads.py | 61 - .../api/employees/__init__.py | 0 .../api/employees/get_employee.py | 74 - .../api/employees/get_employees.py | 87 - .../api/messages/__init__.py | 0 .../api/messages/create_message.py | 108 -- .../api/messages/get_list_message.py | 106 -- .../api/messages/get_message.py | 75 - .../api/messages/put_messages_id.py | 104 -- .../api/reactions_to_messages/__init__.py | 0 .../delete_message_reactions.py | 92 - .../get_message_reactions.py | 96 -- .../post_message_reactions.py | 106 -- .../api/reminders/__init__.py | 0 .../api/reminders/post_tasks.py | 91 - .../api/status/__init__.py | 0 .../api/status/del_status.py | 36 - .../api/status/get_status.py | 61 - .../api/status/put_status.py | 82 - .../api/tags/__init__.py | 0 .../api/tags/get_tag.py | 73 - .../api/tags/get_tags.py | 86 - .../api/tags/get_tags_employees.py | 94 -- .../talk_and_channel_participants/__init__.py | 0 .../delete_chats_id_leave.py | 85 - .../post_members_to_chats.py | 89 - .../post_tags_to_chats.py | 89 - .../pachca_api_open_api_3_0_client/client.py | 1489 ----------------- .../pachca_api_open_api_3_0_client/errors.py | 16 - .../models/__init__.py | 189 --- .../models/bad_request.py | 67 - .../models/base_employee.py | 186 -- .../base_employee_custom_properties_item.py | 85 - .../models/button.py | 78 - .../models/chat.py | 162 -- .../models/create_chat_body.py | 71 - .../models/create_chat_response_201.py | 71 - .../models/create_chat_response_400.py | 74 - .../models/create_chat_response_404.py | 74 - .../models/create_chat_response_422.py | 74 - .../models/create_message.py | 178 -- .../models/create_message_body.py | 71 - .../models/create_message_entity_type.py | 10 - .../models/create_message_files_item.py | 84 - .../create_message_files_item_file_type.py | 9 - .../models/create_message_response_201.py | 71 - .../models/create_thread_response_200.py | 71 - .../models/create_thread_response_200_data.py | 104 -- .../delete_message_reactions_response_400.py | 76 - ...sage_reactions_response_400_errors_item.py | 111 -- ...ctions_response_400_errors_item_payload.py | 43 - .../delete_message_reactions_response_404.py | 76 - ...sage_reactions_response_404_errors_item.py | 111 -- ...ctions_response_404_errors_item_payload.py | 43 - .../models/direct_response.py | 195 --- .../models/edit_messages.py | 113 -- .../models/edit_messages_buttons_item_item.py | 76 - .../models/edit_messages_files.py | 95 -- .../models/edit_messages_files_file_type.py | 9 - .../models/employee.py | 275 --- .../models/error.py | 107 -- .../models/error_payload.py | 43 - .../models/errors_code.py | 108 -- .../models/errors_code_payload.py | 43 - .../models/file_response.py | 130 -- .../models/get_chat_response_200.py | 71 - .../models/get_chat_response_404.py | 74 - .../models/get_chats_availability.py | 9 - .../models/get_chats_response_200.py | 74 - .../models/get_chats_response_400.py | 71 - .../models/get_chats_response_404.py | 74 - .../models/get_chats_response_422.py | 74 - .../models/get_chats_sortid.py | 9 - .../models/get_common_methods_response_200.py | 74 - .../models/get_employee_response_200.py | 71 - .../models/get_employees_response_200.py | 74 - .../models/get_list_message_response_200.py | 74 - .../models/get_message_reactions_body.py | 68 - .../get_message_reactions_response_200.py | 74 - .../models/get_message_response_200.py | 71 - .../models/get_status_response_200.py | 88 - .../models/get_tag_response_200.py | 71 - .../models/get_tag_response_404.py | 74 - .../get_tag_response_404_errors_item.py | 107 -- ...et_tag_response_404_errors_item_payload.py | 43 - .../models/get_tags_employees_response_200.py | 74 - .../models/get_tags_response_200.py | 74 - .../models/get_tags_response_400.py | 74 - .../get_tags_response_400_errors_item.py | 107 -- ...t_tags_response_400_errors_item_payload.py | 43 - .../models/message.py | 272 --- .../models/message_entity_type.py | 10 - .../models/message_files_item.py | 104 -- .../models/message_files_item_file_type.py | 9 - .../models/message_forwarding.py | 153 -- .../models/message_thread.py | 67 - .../models/not_found.py | 59 - .../models/post_members_to_chats_body.py | 69 - .../models/post_message_reactions_body.py | 58 - .../post_message_reactions_response_400.py | 58 - .../post_message_reactions_response_403.py | 58 - .../post_message_reactions_response_404.py | 58 - .../models/post_tags_to_chats_body.py | 58 - .../models/post_tasks_body.py | 71 - .../models/post_tasks_body_task.py | 123 -- ..._tasks_body_task_custom_properties_item.py | 67 - .../models/post_tasks_response_201.py | 71 - .../models/post_tasks_response_201_data.py | 177 -- ...esponse_201_data_custom_properties_item.py | 85 - .../models/post_tasks_response_400.py | 58 - .../models/put_messages_id_body.py | 72 - .../models/put_messages_id_response_200.py | 74 - .../models/put_status_response_201.py | 88 - .../models/query_chat.py | 91 - .../models/query_common_methods.py | 77 - .../models/query_status.py | 71 - .../models/query_status_status.py | 102 -- .../models/reaction.py | 86 - .../models/status_type_0.py | 101 -- .../models/tag.py | 77 - .../pachca_api_open_api_3_0_client/py.typed | 1 - .../pachca_api_open_api_3_0_client/types.py | 46 - pachca-api-open-api-3-0-client/pyproject.toml | 27 - requirements.txt | 27 - src/generator1/README.md | 22 + openapi.yaml => src/generator1/openapi.yaml | 0 pachca.py => src/generator1/pachca.py | 12 +- script.py => src/generator1/script.py | 0 .../generator1/templates}/client.py.jinja | 0 .../templates}/endpoint_macros.py.jinja | 0 .../templates}/endpoint_module.py.jinja | 0 .../templates}/macros/client_macros.py.jinja | 0 src/generator2/README.md | 4 + src/repository/README.md | 1 + src/requirements.txt | 28 +- 149 files changed, 61 insertions(+), 11614 deletions(-) delete mode 100644 pachca-api-open-api-3-0-client/.gitignore delete mode 100644 pachca-api-open-api-3-0-client/README.md delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed delete mode 100644 pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py delete mode 100644 pachca-api-open-api-3-0-client/pyproject.toml delete mode 100644 requirements.txt create mode 100644 src/generator1/README.md rename openapi.yaml => src/generator1/openapi.yaml (100%) rename pachca.py => src/generator1/pachca.py (68%) rename script.py => src/generator1/script.py (100%) rename {templates => src/generator1/templates}/client.py.jinja (100%) rename {templates => src/generator1/templates}/endpoint_macros.py.jinja (100%) rename {templates => src/generator1/templates}/endpoint_module.py.jinja (100%) rename {templates => src/generator1/templates}/macros/client_macros.py.jinja (100%) create mode 100644 src/generator2/README.md create mode 100644 src/repository/README.md diff --git a/.gitignore b/.gitignore index 94ae0ac..6b08980 100644 --- a/.gitignore +++ b/.gitignore @@ -164,5 +164,4 @@ cython_debug/ .idea/ .vscode/ - pachca-api-open-api-3-0-client/ \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/.gitignore b/pachca-api-open-api-3-0-client/.gitignore deleted file mode 100644 index 79a2c3d..0000000 --- a/pachca-api-open-api-3-0-client/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -__pycache__/ -build/ -dist/ -*.egg-info/ -.pytest_cache/ - -# pyenv -.python-version - -# Environments -.env -.venv - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# JetBrains -.idea/ - -/coverage.xml -/.coverage diff --git a/pachca-api-open-api-3-0-client/README.md b/pachca-api-open-api-3-0-client/README.md deleted file mode 100644 index 3bb71ab..0000000 --- a/pachca-api-open-api-3-0-client/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# pachca-api-open-api-3-0-client -A client library for accessing PachcaAPI - OpenAPI 3.0 - -## Usage -First, create a client: - -```python -from pachca_api_open_api_3_0_client import Client - -client = Client(base_url="https://api.example.com") -``` - -If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: - -```python -from pachca_api_open_api_3_0_client import AuthenticatedClient - -client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") -``` - -Now call your endpoint and use your models: - -```python -from pachca_api_open_api_3_0_client.models import MyDataModel -from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model -from pachca_api_open_api_3_0_client.types import Response - -with client as client: - my_data: MyDataModel = get_my_data_model.sync(client=client) - # or if you need more info (e.g. status_code) - response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) -``` - -Or do the same thing with an async version: - -```python -from pachca_api_open_api_3_0_client.models import MyDataModel -from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model -from pachca_api_open_api_3_0_client.types import Response - -async with client as client: - my_data: MyDataModel = await get_my_data_model.asyncio(client=client) - response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) -``` - -By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. - -```python -client = AuthenticatedClient( - base_url="https://internal_api.example.com", - token="SuperSecretToken", - verify_ssl="/path/to/certificate_bundle.pem", -) -``` - -You can also disable certificate validation altogether, but beware that **this is a security risk**. - -```python -client = AuthenticatedClient( - base_url="https://internal_api.example.com", - token="SuperSecretToken", - verify_ssl=False -) -``` - -Things to know: -1. Every path/method combo becomes a Python module with four functions: - 1. `sync`: Blocking request that returns parsed data (if successful) or `None` - 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. - 1. `asyncio`: Like `sync` but async instead of blocking - 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking - -1. All path/query params, and bodies become method arguments. -1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) -1. Any endpoint which did not have a tag will be in `pachca_api_open_api_3_0_client.api.default` - -## Advanced customizations - -There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): - -```python -from pachca_api_open_api_3_0_client import Client - -def log_request(request): - print(f"Request event hook: {request.method} {request.url} - Waiting for response") - -def log_response(response): - request = response.request - print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") - -client = Client( - base_url="https://api.example.com", - httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, -) - -# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() -``` - -You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): - -```python -import httpx -from pachca_api_open_api_3_0_client import Client - -client = Client( - base_url="https://api.example.com", -) -# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. -client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) -``` - -## Building / publishing this package -This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: -1. Update the metadata in pyproject.toml (e.g. authors, version) -1. If you're using a private repository, configure it with Poetry - 1. `poetry config repositories. ` - 1. `poetry config http-basic. ` -1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` - -If you want to install this client into another project without publishing it (e.g. for development) then: -1. If that project **is using Poetry**, you can simply do `poetry add ` from that project -1. If that project is not using Poetry: - 1. Build a wheel with `poetry build -f wheel` - 1. Install that wheel from the other project `pip install ` diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py deleted file mode 100644 index 3a6c9f0..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""A client library for accessing PachcaAPI - OpenAPI 3.0""" - -from .client import AuthenticatedClient, Client - -__all__ = ( - "AuthenticatedClient", - "Client", -) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py deleted file mode 100644 index 81f9fa2..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Contains methods for accessing the API""" diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py deleted file mode 100644 index 89cdc5a..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py +++ /dev/null @@ -1,97 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.create_chat_body import CreateChatBody -from ...models.create_chat_response_201 import CreateChatResponse201 -from ...models.create_chat_response_400 import CreateChatResponse400 -from ...models.create_chat_response_404 import CreateChatResponse404 -from ...models.create_chat_response_422 import CreateChatResponse422 -from ...types import Response - - -def _get_kwargs_createChat( - self, - body: CreateChatBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/chats", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_createChat( - self, response: httpx.Response -) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) - - return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createChat( - self, response: httpx.Response -) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createChat(response=response), - ) - - -async def createChat( - self, - body: CreateChatBody, -) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - r""" Новая беседа или канал - - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ - - Args: - body (CreateChatBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - - kwargs = self._get_kwargs_createChat( - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_createChat(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py deleted file mode 100644 index e134dd6..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py +++ /dev/null @@ -1,74 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_chat_response_200 import GetChatResponse200 -from ...models.get_chat_response_404 import GetChatResponse404 -from ...types import Response - - -def _get_kwargs_getChat( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/chats/{id}", - } - - return _kwargs - - -def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getChat(response=response), - ) - - -async def getChat( - self, - id: int, -) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале - - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatResponse200, GetChatResponse404] - """ - - kwargs = self._get_kwargs_getChat( - id=id, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getChat(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py deleted file mode 100644 index bebb456..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py +++ /dev/null @@ -1,142 +0,0 @@ -import datetime -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_chats_availability import GetChatsAvailability -from ...models.get_chats_response_200 import GetChatsResponse200 -from ...models.get_chats_response_400 import GetChatsResponse400 -from ...models.get_chats_response_404 import GetChatsResponse404 -from ...models.get_chats_response_422 import GetChatsResponse422 -from ...models.get_chats_sortid import GetChatsSortid -from ...types import UNSET, Response, Unset - - -def _get_kwargs_getChats( - self, - sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, - availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, - last_message_at_after: Union[Unset, datetime.datetime] = UNSET, - last_message_at_before: Union[Unset, datetime.datetime] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - - params["sort[id]"] = json_sortid - - params["per"] = per - - params["page"] = page - - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - - params["availability"] = json_availability - - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params["last_message_at_after"] = json_last_message_at_after - - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params["last_message_at_before"] = json_last_message_at_before - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/chats", - "params": params, - } - - return _kwargs - - -def _parse_response_getChats( - self, response: httpx.Response -) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getChats( - self, response: httpx.Response -) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getChats(response=response), - ) - - -async def getChats( - self, - sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, - availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, - last_message_at_after: Union[Unset, datetime.datetime] = UNSET, - last_message_at_before: Union[Unset, datetime.datetime] = UNSET, -) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - - kwargs = self._get_kwargs_getChats( - sortid=sortid, - per=per, - page=page, - availability=availability, - last_message_at_after=last_message_at_after, - last_message_at_before=last_message_at_before, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getChats(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py deleted file mode 100644 index eb23656..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/comments/create_thread.py +++ /dev/null @@ -1,83 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.create_thread_response_200 import CreateThreadResponse200 -from ...models.not_found import NotFound -from ...types import Response - - -def _get_kwargs_createThread( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/messages/{id}/thread", - } - - return _kwargs - - -def _parse_response_createThread( - self, response: httpx.Response -) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createThread( - self, response: httpx.Response -) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createThread(response=response), - ) - - -async def createThread( - self, - id: int, -) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - - kwargs = self._get_kwargs_createThread( - id=id, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_createThread(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py deleted file mode 100644 index 7eeb703..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py +++ /dev/null @@ -1,85 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from ...types import UNSET, Response - - -def _get_kwargs_getCommonMethods( - self, - entity_type: str, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["entity_type"] = entity_type - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/custom_properties", - "params": params, - } - - return _kwargs - - -def _parse_response_getCommonMethods( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getCommonMethods( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getCommonMethods(response=response), - ) - - -async def getCommonMethods( - self, - entity_type: str, -) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetCommonMethodsResponse200] - """ - - kwargs = self._get_kwargs_getCommonMethods( - entity_type=entity_type, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getCommonMethods(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py deleted file mode 100644 index 49b24c6..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py +++ /dev/null @@ -1,45 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...models.direct_response import DirectResponse -from ...types import Response - - -def _get_kwargs_getDirectUrl( - self, - body: DirectResponse, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/direct_url", - } - - _body = body.to_multipart() - - _kwargs["files"] = _body - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getDirectUrl(response=response), - ) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py deleted file mode 100644 index b5ddcd3..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py +++ /dev/null @@ -1,61 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...models.file_response import FileResponse -from ...types import Response - - -def _get_kwargs_getUploads( - self, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/uploads", - } - - return _kwargs - - -def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: - if response.status_code == 200: - response_200 = FileResponse.from_dict(response.json()) - - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getUploads(response=response), - ) - - -async def getUploads( - self, -) -> Optional[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - FileResponse - """ - - kwargs = self._get_kwargs_getUploads() - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getUploads(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py deleted file mode 100644 index 5f758db..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employee.py +++ /dev/null @@ -1,74 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_employee_response_200 import GetEmployeeResponse200 -from ...models.not_found import NotFound -from ...types import Response - - -def _get_kwargs_getEmployee( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/users/{id}", - } - - return _kwargs - - -def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getEmployee(response=response), - ) - - -async def getEmployee( - self, - id: int, -) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetEmployeeResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getEmployee( - id=id, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getEmployee(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py deleted file mode 100644 index d68f825..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/employees/get_employees.py +++ /dev/null @@ -1,87 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_employees_response_200 import GetEmployeesResponse200 -from ...types import UNSET, Response, Unset - - -def _get_kwargs_getEmployees( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, - query: Union[Unset, str] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["per"] = per - - params["page"] = page - - params["query"] = query - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/users", - "params": params, - } - - return _kwargs - - -def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: - if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) - - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getEmployees(response=response), - ) - - -async def getEmployees( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, - query: Union[Unset, str] = UNSET, -) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetEmployeesResponse200 - """ - - kwargs = self._get_kwargs_getEmployees( - per=per, - page=page, - query=query, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getEmployees(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py deleted file mode 100644 index 89fccb4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/create_message.py +++ /dev/null @@ -1,108 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.create_message_body import CreateMessageBody -from ...models.create_message_response_201 import CreateMessageResponse201 -from ...models.error import Error -from ...types import Response - - -def _get_kwargs_createMessage( - self, - body: CreateMessageBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/messages", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_createMessage( - self, response: httpx.Response -) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - if response.status_code == 201: - response_201 = CreateMessageResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for componentsschemas_errors_item_data in _response_404: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - response_404.append(componentsschemas_errors_item) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createMessage( - self, response: httpx.Response -) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createMessage(response=response), - ) - - -async def createMessage( - self, - body: CreateMessageBody, -) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - r"""создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \"discussion\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \"user\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - - Args: - body (CreateMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] - """ - - kwargs = self._get_kwargs_createMessage( - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_createMessage(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py deleted file mode 100644 index 090f093..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_list_message.py +++ /dev/null @@ -1,106 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_list_message_response_200 import GetListMessageResponse200 -from ...models.not_found import NotFound -from ...types import UNSET, Response, Unset - - -def _get_kwargs_getListMessage( - self, - chat_id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["chat_id"] = chat_id - - params["per"] = per - - params["page"] = page - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/messages", - "params": params, - } - - return _kwargs - - -def _parse_response_getListMessage( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetListMessageResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getListMessage( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getListMessage(response=response), - ) - - -async def getListMessage( - self, - chat_id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - - Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetListMessageResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getListMessage( - chat_id=chat_id, - per=per, - page=page, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getListMessage(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py deleted file mode 100644 index 83f1f22..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/get_message.py +++ /dev/null @@ -1,75 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_message_response_200 import GetMessageResponse200 -from ...models.not_found import NotFound -from ...types import Response - - -def _get_kwargs_getMessage( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/messages/{id}", - } - - return _kwargs - - -def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getMessage(response=response), - ) - - -async def getMessage( - self, - id: int, -) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetMessageResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getMessage( - id=id, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getMessage(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py deleted file mode 100644 index 6593577..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/messages/put_messages_id.py +++ /dev/null @@ -1,104 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...models.put_messages_id_body import PutMessagesIdBody -from ...models.put_messages_id_response_200 import PutMessagesIdResponse200 -from ...types import Response - - -def _get_kwargs_put_messages_id( - self, - id: int, - body: PutMessagesIdBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "put", - "url": f"/messages/{id}", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_put_messages_id( - self, response: httpx.Response -) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: - if response.status_code == 200: - response_200 = PutMessagesIdResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - - response_404.append(response_404_item) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_put_messages_id( - self, response: httpx.Response -) -> Response[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_put_messages_id(response=response), - ) - - -async def put_messages_id( - self, - id: int, - body: PutMessagesIdBody, -) -> Optional[Union[PutMessagesIdResponse200, list["ErrorsCode"]]]: - """Редактирование сообщения - - Метод для редактирования сообщения или комментария. - - Args: - id (int): - body (PutMessagesIdBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PutMessagesIdResponse200, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_put_messages_id( - id=id, - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_put_messages_id(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py deleted file mode 100644 index 92090b4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py +++ /dev/null @@ -1,92 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from ...types import UNSET, Response - - -def _get_kwargs_deleteMessageReactions( - self, - id: int, - code: str, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["code"] = code - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "delete", - "url": f"/messages/{id}/reactions", - "params": params, - } - - return _kwargs - - -def _parse_response_deleteMessageReactions( - self, response: httpx.Response -) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_deleteMessageReactions( - self, response: httpx.Response -) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_deleteMessageReactions(response=response), - ) - - -async def deleteMessageReactions( - self, - id: int, - code: str, -) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. - - Args: - id (int): - code (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] - """ - - kwargs = self._get_kwargs_deleteMessageReactions( - id=id, - code=code, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_deleteMessageReactions(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py deleted file mode 100644 index e2721f1..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py +++ /dev/null @@ -1,96 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_message_reactions_body import GetMessageReactionsBody -from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from ...models.not_found import NotFound -from ...types import Response - - -def _get_kwargs_getMessageReactions( - self, - id: int, - body: GetMessageReactionsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/messages/{id}/reactions", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_getMessageReactions( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getMessageReactions( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getMessageReactions(response=response), - ) - - -async def getMessageReactions( - self, - id: int, - body: GetMessageReactionsBody, -) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. - - Args: - id (int): - body (GetMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getMessageReactions( - id=id, - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getMessageReactions(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py deleted file mode 100644 index 7386098..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py +++ /dev/null @@ -1,106 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.post_message_reactions_body import PostMessageReactionsBody -from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 -from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from ...types import Response - - -def _get_kwargs_postMessageReactions( - self, - id: int, - body: PostMessageReactionsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/messages/{id}/reactions", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_postMessageReactions( - self, response: httpx.Response -) -> Optional[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_postMessageReactions( - self, response: httpx.Response -) -> Response[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_postMessageReactions(response=response), - ) - - -async def postMessageReactions( - self, - id: int, - body: PostMessageReactionsBody, -) -> Optional[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (int): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] - """ - - kwargs = self._get_kwargs_postMessageReactions( - id=id, - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_postMessageReactions(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py deleted file mode 100644 index a149f83..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/reminders/post_tasks.py +++ /dev/null @@ -1,91 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.post_tasks_body import PostTasksBody -from ...models.post_tasks_response_201 import PostTasksResponse201 -from ...models.post_tasks_response_400 import PostTasksResponse400 -from ...types import Response - - -def _get_kwargs_post_tasks( - self, - body: PostTasksBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/tasks", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_post_tasks( - self, response: httpx.Response -) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - if response.status_code == 201: - response_201 = PostTasksResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 400: - response_400 = PostTasksResponse400.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_post_tasks( - self, response: httpx.Response -) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_post_tasks(response=response), - ) - - -async def post_tasks( - self, - body: PostTasksBody, -) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (PostTasksBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PostTasksResponse201, PostTasksResponse400] - """ - - kwargs = self._get_kwargs_post_tasks( - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_post_tasks(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py deleted file mode 100644 index 343eec6..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/del_status.py +++ /dev/null @@ -1,36 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...types import Response - - -def _get_kwargs_delStatus( - self, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "delete", - "url": "/profile/status", - } - - return _kwargs - - -def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_delStatus(response=response), - ) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py deleted file mode 100644 index f0ebcd7..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/get_status.py +++ /dev/null @@ -1,61 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...models.get_status_response_200 import GetStatusResponse200 -from ...types import Response - - -def _get_kwargs_getStatus( - self, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/profile/status", - } - - return _kwargs - - -def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: - if response.status_code == 200: - response_200 = GetStatusResponse200.from_dict(response.json()) - - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getStatus(response=response), - ) - - -async def getStatus( - self, -) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetStatusResponse200 - """ - - kwargs = self._get_kwargs_getStatus() - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getStatus(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py deleted file mode 100644 index 1211045..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/status/put_status.py +++ /dev/null @@ -1,82 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.put_status_response_201 import PutStatusResponse201 -from ...models.query_status import QueryStatus -from ...types import Response - - -def _get_kwargs_putStatus( - self, - body: QueryStatus, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "put", - "url": "/profile/status", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: - if response.status_code == 201: - response_201 = PutStatusResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_putStatus(response=response), - ) - - -async def putStatus( - self, - body: QueryStatus, -) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус - - Создание нового статуса. - - Args: - body (QueryStatus): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, PutStatusResponse201] - """ - - kwargs = self._get_kwargs_putStatus( - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_putStatus(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py deleted file mode 100644 index 4f0b49f..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tag.py +++ /dev/null @@ -1,73 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_tag_response_200 import GetTagResponse200 -from ...models.get_tag_response_404 import GetTagResponse404 -from ...types import Response - - -def _get_kwargs_getTag( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/group_tags/{id}", - } - - return _kwargs - - -def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - if response.status_code == 200: - response_200 = GetTagResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = GetTagResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getTag(response=response), - ) - - -async def getTag( - self, - id: int, -) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге - - Параметры запроса отсутствуют - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagResponse200, GetTagResponse404] - """ - - kwargs = self._get_kwargs_getTag( - id=id, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getTag(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py deleted file mode 100644 index 9710704..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags.py +++ /dev/null @@ -1,86 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_tags_response_200 import GetTagsResponse200 -from ...models.get_tags_response_400 import GetTagsResponse400 -from ...types import UNSET, Response, Unset - - -def _get_kwargs_getTags( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["per"] = per - - params["page"] = page - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/group_tags", - "params": params, - } - - return _kwargs - - -def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getTags(response=response), - ) - - -async def getTags( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, -) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagsResponse200, GetTagsResponse400] - """ - - kwargs = self._get_kwargs_getTags( - per=per, - page=page, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getTags(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py deleted file mode 100644 index d259ecd..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py +++ /dev/null @@ -1,94 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from ...types import UNSET, Response, Unset - - -def _get_kwargs_getTagsEmployees( - self, - id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["per"] = per - - params["page"] = page - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/group_tags/{id}/users", - "params": params, - } - - return _kwargs - - -def _parse_response_getTagsEmployees( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getTagsEmployees( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getTagsEmployees(response=response), - ) - - -async def getTagsEmployees( - self, - id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetTagsEmployeesResponse200] - """ - - kwargs = self._get_kwargs_getTagsEmployees( - id=id, - per=per, - page=page, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_getTagsEmployees(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py deleted file mode 100644 index cac771d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/delete_chats_id_leave.py +++ /dev/null @@ -1,85 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...types import Response - - -def _get_kwargs_delete_chats_id_leave( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "delete", - "url": f"/chats/{id}/leave", - } - - return _kwargs - - -def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: - if response.status_code == 200: - response_200 = cast(Any, None) - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - - response_404.append(response_404_item) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_delete_chats_id_leave(response=response), - ) - - -async def delete_chats_id_leave( - self, - id: int, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """Выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_delete_chats_id_leave( - id=id, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_delete_chats_id_leave(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py deleted file mode 100644 index 5710447..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py +++ /dev/null @@ -1,89 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...models.post_members_to_chats_body import PostMembersToChatsBody -from ...types import Response - - -def _get_kwargs_postMembersToChats( - self, - id: int, - body: PostMembersToChatsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/chats/{id}/members", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_postMembersToChats(response=response), - ) - - -async def postMembersToChats( - self, - id: int, - body: PostMembersToChatsBody, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostMembersToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_postMembersToChats( - id=id, - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_postMembersToChats(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py deleted file mode 100644 index 1d90b2c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py +++ /dev/null @@ -1,89 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...models.post_tags_to_chats_body import PostTagsToChatsBody -from ...types import Response - - -def _get_kwargs_postTagsToChats( - self, - id: int, - body: PostTagsToChatsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/chats/{id}/group_tags", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_postTagsToChats(response=response), - ) - - -async def postTagsToChats( - self, - id: int, - body: PostTagsToChatsBody, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostTagsToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_postTagsToChats( - id=id, - body=body, - ) - - response = await self.client.get_async_httpx_client().request(**kwargs) - - return self._build_response_postTagsToChats(response=response).parsed diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py deleted file mode 100644 index 961bce4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py +++ /dev/null @@ -1,1489 +0,0 @@ -from .models.get_employee_response_200 import GetEmployeeResponse200 -from .models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from .models.get_message_response_200 import GetMessageResponse200 -from .models.get_chats_response_200 import GetChatsResponse200 -from .models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .models.create_chat_response_404 import CreateChatResponse404 -from .models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from .models.get_list_message_response_200 import GetListMessageResponse200 -from .models.get_chats_response_400 import GetChatsResponse400 -from typing import Optional -from .models.post_message_reactions_body import PostMessageReactionsBody -from .types import UNSET -from .models.post_tasks_response_201 import PostTasksResponse201 -from .models.get_chat_response_200 import GetChatResponse200 -from typing import cast -from .models.get_chats_availability import GetChatsAvailability -from .models.get_status_response_200 import GetStatusResponse200 -from .models.create_chat_response_422 import CreateChatResponse422 -from .models.not_found import NotFound -from .models.create_message_body import CreateMessageBody -from .types import Response -from .models.direct_response import DirectResponse -from .models.get_chat_response_404 import GetChatResponse404 -from .models.create_message_response_201 import CreateMessageResponse201 -from .models.create_thread_response_200 import CreateThreadResponse200 -from .models.create_chat_body import CreateChatBody -from .models.query_status import QueryStatus -from .models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from typing import Any -from .models.create_chat_response_201 import CreateChatResponse201 -from .models.get_tag_response_200 import GetTagResponse200 -from .models.get_message_reactions_body import GetMessageReactionsBody -from .models.get_employees_response_200 import GetEmployeesResponse200 -from .models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .models.bad_request import BadRequest -from .models.file_response import FileResponse -from .models.get_tag_response_404 import GetTagResponse404 -from http import HTTPStatus -from .models.get_chats_response_422 import GetChatsResponse422 -from .models.get_tags_response_200 import GetTagsResponse200 -from . import errors -from typing import Union -from .types import Unset -from .models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from .models.error import Error -from .models.get_chats_sortid import GetChatsSortid -from .models.get_chats_response_404 import GetChatsResponse404 -from .models.put_messages_id_body import PutMessagesIdBody -from .models.put_status_response_201 import PutStatusResponse201 -from .models.errors_code import ErrorsCode -from .models.create_chat_response_400 import CreateChatResponse400 -from .models.post_tasks_body import PostTasksBody -from .models.get_tags_response_400 import GetTagsResponse400 -from .models.post_members_to_chats_body import PostMembersToChatsBody -from .models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from .models.post_tasks_response_400 import PostTasksResponse400 -from .models.post_tags_to_chats_body import PostTagsToChatsBody -from .models.put_messages_id_response_200 import PutMessagesIdResponse200 -from .models.post_message_reactions_response_403 import PostMessageReactionsResponse403 - -import datetime -import ssl -from typing import Any, Union, Optional - -from attrs import define, field, evolve -import httpx - - - -@define -class Client: - """A class for keeping track of data related to the API - - - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field( - default="https://api.pachca.com/api/shared/v1", - kw_only=True, - alias="base_url" - ) - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - - def with_headers(self, headers: dict[str, str]) -> "Client": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "Client": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "Client": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - - def set_httpx_client(self, client: httpx.Client) -> "Client": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "Client": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "Client": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field( - default="https://api.pachca.com/api/shared/v1", - kw_only=True, - alias="base_url" - ) - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -class Pachca: - """Главный класс библиотеки.""" - - def __init__(self, token): - self.client = AuthenticatedClient(token=token) - - - - def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} - return _kwargs - - def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) - - async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - kwargs = self._get_kwargs_createThread(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createThread(response=response).parsed - - def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['entity_type'] = entity_type - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} - return _kwargs - - def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) - - async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetCommonMethodsResponse200] - """ - kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getCommonMethods(response=response).parsed - - def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} - _body = body.to_multipart() - _kwargs['files'] = _body - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) - - def _get_kwargs_getUploads(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} - return _kwargs - - def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: - if response.status_code == 200: - response_200 = FileResponse.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) - - async def getUploads(self) -> Optional[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - FileResponse - """ - kwargs = self._get_kwargs_getUploads() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getUploads(response=response).parsed - - def _get_kwargs_put_messages_id(self, id: int, body: PutMessagesIdBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_put_messages_id(self, response: httpx.Response) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = PutMessagesIdResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_put_messages_id(self, response: httpx.Response) -> Response[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_put_messages_id(response=response)) - - async def put_messages_id(self, id: int, body: PutMessagesIdBody) -> Optional[Union[PutMessagesIdResponse200, list['ErrorsCode']]]: - """Редактирование сообщения - - Метод для редактирования сообщения или комментария. - - Args: - id (int): - body (PutMessagesIdBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PutMessagesIdResponse200, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_put_messages_id(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_put_messages_id(response=response).parsed - - def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - if response.status_code == 201: - response_201 = CreateMessageResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for componentsschemas_errors_item_data in _response_404: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - response_404.append(componentsschemas_errors_item) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) - - async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - - Args: - body (CreateMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] - """ - kwargs = self._get_kwargs_createMessage(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createMessage(response=response).parsed - - def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} - return _kwargs - - def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) - - async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetMessageResponse200, NotFound] - """ - kwargs = self._get_kwargs_getMessage(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessage(response=response).parsed - - def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['chat_id'] = chat_id - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} - return _kwargs - - def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetListMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) - - async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - - Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetListMessageResponse200, NotFound] - """ - kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getListMessage(response=response).parsed - - def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) - - async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostTagsToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postTagsToChats(response=response).parsed - - def _get_kwargs_delete_chats_id_leave(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} - return _kwargs - - def _parse_response_delete_chats_id_leave(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = cast(Any, None) - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_delete_chats_id_leave(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delete_chats_id_leave(response=response)) - - async def delete_chats_id_leave(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_delete_chats_id_leave(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_delete_chats_id_leave(response=response).parsed - - def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) - - async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostMembersToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMembersToChats(response=response).parsed - - def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} - return _kwargs - - def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) - - async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале - - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatResponse200, GetChatResponse404] - """ - kwargs = self._get_kwargs_getChat(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChat(response=response).parsed - - def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) - - async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал - - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ - - Args: - body (CreateChatBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - kwargs = self._get_kwargs_createChat(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_createChat(response=response).parsed - - def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - params['sort[id]'] = json_sortid - params['per'] = per - params['page'] = page - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - params['availability'] = json_availability - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params['last_message_at_after'] = json_last_message_at_after - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params['last_message_at_before'] = json_last_message_at_before - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} - return _kwargs - - def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) - - async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getChats(response=response).parsed - - def _get_kwargs_getStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} - return _kwargs - - def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: - if response.status_code == 200: - response_200 = GetStatusResponse200.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) - - async def getStatus(self) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetStatusResponse200 - """ - kwargs = self._get_kwargs_getStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getStatus(response=response).parsed - - def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: - if response.status_code == 201: - response_201 = PutStatusResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) - - async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус - - Создание нового статуса. - - Args: - body (QueryStatus): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, PutStatusResponse201] - """ - kwargs = self._get_kwargs_putStatus(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_putStatus(response=response).parsed - - def _get_kwargs_delStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} - return _kwargs - - def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) - - def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} - return _kwargs - - def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - - async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagsResponse200, GetTagsResponse400] - """ - kwargs = self._get_kwargs_getTags(per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTags(response=response).parsed - - def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} - return _kwargs - - def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - if response.status_code == 200: - response_200 = GetTagResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = GetTagResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) - - async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге - - Параметры запроса отсутствуют - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagResponse200, GetTagResponse404] - """ - kwargs = self._get_kwargs_getTag(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTag(response=response).parsed - - def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} - return _kwargs - - def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - - async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetTagsEmployeesResponse200] - """ - kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getTagsEmployees(response=response).parsed - - def _get_kwargs_post_tasks(self, body: PostTasksBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_post_tasks(self, response: httpx.Response) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - if response.status_code == 201: - response_201 = PostTasksResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = PostTasksResponse400.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_post_tasks(self, response: httpx.Response) -> Response[Union[PostTasksResponse201, PostTasksResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_post_tasks(response=response)) - - async def post_tasks(self, body: PostTasksBody) -> Optional[Union[PostTasksResponse201, PostTasksResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (PostTasksBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[PostTasksResponse201, PostTasksResponse400] - """ - kwargs = self._get_kwargs_post_tasks(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_post_tasks(response=response).parsed - - def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - - async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (int): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] - """ - kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_postMessageReactions(response=response).parsed - - def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) - - async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. - - Args: - id (int): - body (GetMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] - """ - kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getMessageReactions(response=response).parsed - - def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['code'] = code - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} - return _kwargs - - def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) - - async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. - - Args: - id (int): - code (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] - """ - kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_deleteMessageReactions(response=response).parsed - - def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params['query'] = query - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} - return _kwargs - - def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: - if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) - - async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetEmployeesResponse200 - """ - kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployees(response=response).parsed - - def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} - return _kwargs - - def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) - - async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetEmployeeResponse200, NotFound] - """ - kwargs = self._get_kwargs_getEmployee(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) - return self._build_response_getEmployee(response=response).parsed - - - \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py deleted file mode 100644 index 5f92e76..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/errors.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Contains shared errors types that can be raised from API functions""" - - -class UnexpectedStatus(Exception): - """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" - - def __init__(self, status_code: int, content: bytes): - self.status_code = status_code - self.content = content - - super().__init__( - f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" - ) - - -__all__ = ["UnexpectedStatus"] diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py deleted file mode 100644 index bf2d6c3..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/__init__.py +++ /dev/null @@ -1,189 +0,0 @@ -"""Contains all the data models used in inputs/outputs""" - -from .bad_request import BadRequest -from .base_employee import BaseEmployee -from .base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem -from .button import Button -from .chat import Chat -from .create_chat_body import CreateChatBody -from .create_chat_response_201 import CreateChatResponse201 -from .create_chat_response_400 import CreateChatResponse400 -from .create_chat_response_404 import CreateChatResponse404 -from .create_chat_response_422 import CreateChatResponse422 -from .create_message import CreateMessage -from .create_message_body import CreateMessageBody -from .create_message_entity_type import CreateMessageEntityType -from .create_message_files_item import CreateMessageFilesItem -from .create_message_files_item_file_type import CreateMessageFilesItemFileType -from .create_message_response_201 import CreateMessageResponse201 -from .create_thread_response_200 import CreateThreadResponse200 -from .create_thread_response_200_data import CreateThreadResponse200Data -from .delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from .delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem -from .delete_message_reactions_response_400_errors_item_payload import ( - DeleteMessageReactionsResponse400ErrorsItemPayload, -) -from .delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem -from .delete_message_reactions_response_404_errors_item_payload import ( - DeleteMessageReactionsResponse404ErrorsItemPayload, -) -from .direct_response import DirectResponse -from .edit_messages import EditMessages -from .edit_messages_buttons_item_item import EditMessagesButtonsItemItem -from .edit_messages_files import EditMessagesFiles -from .edit_messages_files_file_type import EditMessagesFilesFileType -from .employee import Employee -from .error import Error -from .error_payload import ErrorPayload -from .errors_code import ErrorsCode -from .errors_code_payload import ErrorsCodePayload -from .file_response import FileResponse -from .get_chat_response_200 import GetChatResponse200 -from .get_chat_response_404 import GetChatResponse404 -from .get_chats_availability import GetChatsAvailability -from .get_chats_response_200 import GetChatsResponse200 -from .get_chats_response_400 import GetChatsResponse400 -from .get_chats_response_404 import GetChatsResponse404 -from .get_chats_response_422 import GetChatsResponse422 -from .get_chats_sortid import GetChatsSortid -from .get_common_methods_response_200 import GetCommonMethodsResponse200 -from .get_employee_response_200 import GetEmployeeResponse200 -from .get_employees_response_200 import GetEmployeesResponse200 -from .get_list_message_response_200 import GetListMessageResponse200 -from .get_message_reactions_body import GetMessageReactionsBody -from .get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .get_message_response_200 import GetMessageResponse200 -from .get_status_response_200 import GetStatusResponse200 -from .get_tag_response_200 import GetTagResponse200 -from .get_tag_response_404 import GetTagResponse404 -from .get_tag_response_404_errors_item import GetTagResponse404ErrorsItem -from .get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload -from .get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from .get_tags_response_200 import GetTagsResponse200 -from .get_tags_response_400 import GetTagsResponse400 -from .get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem -from .get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload -from .message import Message -from .message_entity_type import MessageEntityType -from .message_files_item import MessageFilesItem -from .message_files_item_file_type import MessageFilesItemFileType -from .message_forwarding import MessageForwarding -from .message_thread import MessageThread -from .not_found import NotFound -from .post_members_to_chats_body import PostMembersToChatsBody -from .post_message_reactions_body import PostMessageReactionsBody -from .post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .post_message_reactions_response_403 import PostMessageReactionsResponse403 -from .post_message_reactions_response_404 import PostMessageReactionsResponse404 -from .post_tags_to_chats_body import PostTagsToChatsBody -from .post_tasks_body import PostTasksBody -from .post_tasks_body_task import PostTasksBodyTask -from .post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem -from .post_tasks_response_201 import PostTasksResponse201 -from .post_tasks_response_201_data import PostTasksResponse201Data -from .post_tasks_response_201_data_custom_properties_item import PostTasksResponse201DataCustomPropertiesItem -from .post_tasks_response_400 import PostTasksResponse400 -from .put_messages_id_body import PutMessagesIdBody -from .put_messages_id_response_200 import PutMessagesIdResponse200 -from .put_status_response_201 import PutStatusResponse201 -from .query_chat import QueryChat -from .query_common_methods import QueryCommonMethods -from .query_status import QueryStatus -from .query_status_status import QueryStatusStatus -from .reaction import Reaction -from .status_type_0 import StatusType0 -from .tag import Tag - -__all__ = ( - "BadRequest", - "BaseEmployee", - "BaseEmployeeCustomPropertiesItem", - "Button", - "Chat", - "CreateChatBody", - "CreateChatResponse201", - "CreateChatResponse400", - "CreateChatResponse404", - "CreateChatResponse422", - "CreateMessage", - "CreateMessageBody", - "CreateMessageEntityType", - "CreateMessageFilesItem", - "CreateMessageFilesItemFileType", - "CreateMessageResponse201", - "CreateThreadResponse200", - "CreateThreadResponse200Data", - "DeleteMessageReactionsResponse400", - "DeleteMessageReactionsResponse400ErrorsItem", - "DeleteMessageReactionsResponse400ErrorsItemPayload", - "DeleteMessageReactionsResponse404", - "DeleteMessageReactionsResponse404ErrorsItem", - "DeleteMessageReactionsResponse404ErrorsItemPayload", - "DirectResponse", - "EditMessages", - "EditMessagesButtonsItemItem", - "EditMessagesFiles", - "EditMessagesFilesFileType", - "Employee", - "Error", - "ErrorPayload", - "ErrorsCode", - "ErrorsCodePayload", - "FileResponse", - "GetChatResponse200", - "GetChatResponse404", - "GetChatsAvailability", - "GetChatsResponse200", - "GetChatsResponse400", - "GetChatsResponse404", - "GetChatsResponse422", - "GetChatsSortid", - "GetCommonMethodsResponse200", - "GetEmployeeResponse200", - "GetEmployeesResponse200", - "GetListMessageResponse200", - "GetMessageReactionsBody", - "GetMessageReactionsResponse200", - "GetMessageResponse200", - "GetStatusResponse200", - "GetTagResponse200", - "GetTagResponse404", - "GetTagResponse404ErrorsItem", - "GetTagResponse404ErrorsItemPayload", - "GetTagsEmployeesResponse200", - "GetTagsResponse200", - "GetTagsResponse400", - "GetTagsResponse400ErrorsItem", - "GetTagsResponse400ErrorsItemPayload", - "Message", - "MessageEntityType", - "MessageFilesItem", - "MessageFilesItemFileType", - "MessageForwarding", - "MessageThread", - "NotFound", - "PostMembersToChatsBody", - "PostMessageReactionsBody", - "PostMessageReactionsResponse400", - "PostMessageReactionsResponse403", - "PostMessageReactionsResponse404", - "PostTagsToChatsBody", - "PostTasksBody", - "PostTasksBodyTask", - "PostTasksBodyTaskCustomPropertiesItem", - "PostTasksResponse201", - "PostTasksResponse201Data", - "PostTasksResponse201DataCustomPropertiesItem", - "PostTasksResponse400", - "PutMessagesIdBody", - "PutMessagesIdResponse200", - "PutStatusResponse201", - "QueryChat", - "QueryCommonMethods", - "QueryStatus", - "QueryStatusStatus", - "Reaction", - "StatusType0", - "Tag", -) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py deleted file mode 100644 index 17dd6ed..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/bad_request.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="BadRequest") - - -@_attrs_define -class BadRequest: - """ - Attributes: - error (Union[Unset, str]): - message (Union[Unset, str]): - """ - - error: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - message = self.message - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - if message is not UNSET: - field_dict["message"] = message - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - message = d.pop("message", UNSET) - - bad_request = cls( - error=error, - message=message, - ) - - bad_request.additional_properties = d - return bad_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py deleted file mode 100644 index b6a0314..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee.py +++ /dev/null @@ -1,186 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - - -T = TypeVar("T", bound="BaseEmployee") - - -@_attrs_define -class BaseEmployee: - """Базовый класс сотрудника. - - Attributes: - id (Union[Unset, int]): Идентификатор пользователя Example: 1. - first_name (Union[Unset, str]): Имя - last_name (Union[Unset, str]): Фамилия - nickname (Union[Unset, str]): Имя пользователя - email (Union[Unset, str]): Электронная почта - phone_number (Union[Unset, str]): Телефон - department (Union[Unset, str]): Департамент - role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является - деактивированным. - invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) - list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику - custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника - bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) - """ - - id: Union[Unset, int] = UNSET - first_name: Union[Unset, str] = UNSET - last_name: Union[Unset, str] = UNSET - nickname: Union[Unset, str] = UNSET - email: Union[Unset, str] = UNSET - phone_number: Union[Unset, str] = UNSET - department: Union[Unset, str] = UNSET - role: Union[Unset, str] = UNSET - suspended: Union[Unset, bool] = UNSET - invite_status: Union[Unset, str] = UNSET - list_tags: Union[Unset, list[str]] = UNSET - custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET - bot: Union[Unset, bool] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - first_name = self.first_name - - last_name = self.last_name - - nickname = self.nickname - - email = self.email - - phone_number = self.phone_number - - department = self.department - - role = self.role - - suspended = self.suspended - - invite_status = self.invite_status - - list_tags: Union[Unset, list[str]] = UNSET - if not isinstance(self.list_tags, Unset): - list_tags = self.list_tags - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - bot = self.bot - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if first_name is not UNSET: - field_dict["first_name"] = first_name - if last_name is not UNSET: - field_dict["last_name"] = last_name - if nickname is not UNSET: - field_dict["nickname"] = nickname - if email is not UNSET: - field_dict["email"] = email - if phone_number is not UNSET: - field_dict["phone_number"] = phone_number - if department is not UNSET: - field_dict["department"] = department - if role is not UNSET: - field_dict["role"] = role - if suspended is not UNSET: - field_dict["suspended"] = suspended - if invite_status is not UNSET: - field_dict["invite_status"] = invite_status - if list_tags is not UNSET: - field_dict["list_tags"] = list_tags - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - if bot is not UNSET: - field_dict["bot"] = bot - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - - d = src_dict.copy() - id = d.pop("id", UNSET) - - first_name = d.pop("first_name", UNSET) - - last_name = d.pop("last_name", UNSET) - - nickname = d.pop("nickname", UNSET) - - email = d.pop("email", UNSET) - - phone_number = d.pop("phone_number", UNSET) - - department = d.pop("department", UNSET) - - role = d.pop("role", UNSET) - - suspended = d.pop("suspended", UNSET) - - invite_status = d.pop("invite_status", UNSET) - - list_tags = cast(list[str], d.pop("list_tags", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - bot = d.pop("bot", UNSET) - - base_employee = cls( - id=id, - first_name=first_name, - last_name=last_name, - nickname=nickname, - email=email, - phone_number=phone_number, - department=department, - role=role, - suspended=suspended, - invite_status=invite_status, - list_tags=list_tags, - custom_properties=custom_properties, - bot=bot, - ) - - base_employee.additional_properties = d - return base_employee - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py deleted file mode 100644 index bee25c8..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="BaseEmployeeCustomPropertiesItem") - - -@_attrs_define -class BaseEmployeeCustomPropertiesItem: - """ - Attributes: - id (Union[Unset, int]): Идентификатор поля - name (Union[Unset, str]): Название поля - data_type (Union[Unset, str]): Тип поля (string, number, date или link) - value (Union[Unset, str]): Значение - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - data_type: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - data_type = self.data_type - - value = self.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if data_type is not UNSET: - field_dict["data_type"] = data_type - if value is not UNSET: - field_dict["value"] = value - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - data_type = d.pop("data_type", UNSET) - - value = d.pop("value", UNSET) - - base_employee_custom_properties_item = cls( - id=id, - name=name, - data_type=data_type, - value=value, - ) - - base_employee_custom_properties_item.additional_properties = d - return base_employee_custom_properties_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py deleted file mode 100644 index 64ea323..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/button.py +++ /dev/null @@ -1,78 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Button") - - -@_attrs_define -class Button: - """ - Attributes: - text (str): - url (Union[Unset, str]): - data (Union[Unset, str]): - """ - - text: str - url: Union[Unset, str] = UNSET - data: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - text = self.text - - url = self.url - - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "text": text, - } - ) - if url is not UNSET: - field_dict["url"] = url - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - text = d.pop("text") - - url = d.pop("url", UNSET) - - data = d.pop("data", UNSET) - - button = cls( - text=text, - url=url, - data=data, - ) - - button.additional_properties = d - return button - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py deleted file mode 100644 index 7ef2560..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/chat.py +++ /dev/null @@ -1,162 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Chat") - - -@_attrs_define -class Chat: - """Беседа или канал - - Attributes: - id (Union[Unset, int]): Идентификатор беседы или канала Example: 334. - name (Union[Unset, str]): Название Example: 🤿 aqua. - owner_id (Union[Unset, int]): Идентификатор пользователя, создавшего беседу или канал Example: 185. - created_at (Union[Unset, datetime.datetime]): Дата и время создания беседы или канала (ISO-8601, UTC+0) в - формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:56:53.000Z. - member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, участников Example: [185, 186, 187]. - group_tag_ids (Union[Unset, list[int]]): Массив идентификаторов тегов, участников - channel (Union[Unset, bool]): Тип: беседа (false) или канал (true) Example: True. - public (Union[Unset, bool]): Доступ: закрытый (false) или открытый (true) - last_message_at (Union[Unset, datetime.datetime]): Дата и время создания последнего сообщения в беседе/канале - (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:58:13.000Z. - meet_room_url (Union[Unset, str]): Ссылка на Видеочат Example: https://meet.pachca.com/aqua-94bb21b5. - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - owner_id: Union[Unset, int] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - member_ids: Union[Unset, list[int]] = UNSET - group_tag_ids: Union[Unset, list[int]] = UNSET - channel: Union[Unset, bool] = UNSET - public: Union[Unset, bool] = UNSET - last_message_at: Union[Unset, datetime.datetime] = UNSET - meet_room_url: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - owner_id = self.owner_id - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - member_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.member_ids, Unset): - member_ids = self.member_ids - - group_tag_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.group_tag_ids, Unset): - group_tag_ids = self.group_tag_ids - - channel = self.channel - - public = self.public - - last_message_at: Union[Unset, str] = UNSET - if not isinstance(self.last_message_at, Unset): - last_message_at = self.last_message_at.isoformat() - - meet_room_url = self.meet_room_url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if owner_id is not UNSET: - field_dict["owner_id"] = owner_id - if created_at is not UNSET: - field_dict["created_at"] = created_at - if member_ids is not UNSET: - field_dict["member_ids"] = member_ids - if group_tag_ids is not UNSET: - field_dict["group_tag_ids"] = group_tag_ids - if channel is not UNSET: - field_dict["channel"] = channel - if public is not UNSET: - field_dict["public"] = public - if last_message_at is not UNSET: - field_dict["last_message_at"] = last_message_at - if meet_room_url is not UNSET: - field_dict["meet_room_url"] = meet_room_url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - owner_id = d.pop("owner_id", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - member_ids = cast(list[int], d.pop("member_ids", UNSET)) - - group_tag_ids = cast(list[int], d.pop("group_tag_ids", UNSET)) - - channel = d.pop("channel", UNSET) - - public = d.pop("public", UNSET) - - _last_message_at = d.pop("last_message_at", UNSET) - last_message_at: Union[Unset, datetime.datetime] - if isinstance(_last_message_at, Unset): - last_message_at = UNSET - else: - last_message_at = isoparse(_last_message_at) - - meet_room_url = d.pop("meet_room_url", UNSET) - - chat = cls( - id=id, - name=name, - owner_id=owner_id, - created_at=created_at, - member_ids=member_ids, - group_tag_ids=group_tag_ids, - channel=channel, - public=public, - last_message_at=last_message_at, - meet_room_url=meet_room_url, - ) - - chat.additional_properties = d - return chat - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py deleted file mode 100644 index 8b9e361..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_body.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.query_chat import QueryChat - - -T = TypeVar("T", bound="CreateChatBody") - - -@_attrs_define -class CreateChatBody: - """ - Attributes: - chat (Union[Unset, QueryChat]): Собранный объект параметров создаваемой беседы или канала - """ - - chat: Union[Unset, "QueryChat"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - chat: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.chat, Unset): - chat = self.chat.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if chat is not UNSET: - field_dict["chat"] = chat - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.query_chat import QueryChat - - d = src_dict.copy() - _chat = d.pop("chat", UNSET) - chat: Union[Unset, QueryChat] - if isinstance(_chat, Unset): - chat = UNSET - else: - chat = QueryChat.from_dict(_chat) - - create_chat_body = cls( - chat=chat, - ) - - create_chat_body.additional_properties = d - return create_chat_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py deleted file mode 100644 index 3a928ef..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_201.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.chat import Chat - - -T = TypeVar("T", bound="CreateChatResponse201") - - -@_attrs_define -class CreateChatResponse201: - """ - Attributes: - data (Union[Unset, Chat]): Беседа или канал - """ - - data: Union[Unset, "Chat"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.chat import Chat - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Chat] - if isinstance(_data, Unset): - data = UNSET - else: - data = Chat.from_dict(_data) - - create_chat_response_201 = cls( - data=data, - ) - - create_chat_response_201.additional_properties = d - return create_chat_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py deleted file mode 100644 index 1d7fd30..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_400.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="CreateChatResponse400") - - -@_attrs_define -class CreateChatResponse400: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - create_chat_response_400 = cls( - errors=errors, - ) - - create_chat_response_400.additional_properties = d - return create_chat_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py deleted file mode 100644 index 3de2654..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="CreateChatResponse404") - - -@_attrs_define -class CreateChatResponse404: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - create_chat_response_404 = cls( - errors=errors, - ) - - create_chat_response_404.additional_properties = d - return create_chat_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py deleted file mode 100644 index c917758..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_chat_response_422.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="CreateChatResponse422") - - -@_attrs_define -class CreateChatResponse422: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - create_chat_response_422 = cls( - errors=errors, - ) - - create_chat_response_422.additional_properties = d - return create_chat_response_422 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py deleted file mode 100644 index 63e52de..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message.py +++ /dev/null @@ -1,178 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.create_message_entity_type import CreateMessageEntityType -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.button import Button - from ..models.create_message_files_item import CreateMessageFilesItem - - -T = TypeVar("T", bound="CreateMessage") - - -@_attrs_define -class CreateMessage: - """ - Attributes: - entity_id (int): - content (str): - entity_type (Union[Unset, CreateMessageEntityType]): Default: CreateMessageEntityType.DISCUSSION. - files (Union[Unset, list['CreateMessageFilesItem']]): - buttons (Union[Unset, list[list['Button']]]): - parent_message_id (Union[None, Unset, int]): - skip_invite_mentions (Union[Unset, bool]): Default: False. - link_preview (Union[Unset, bool]): Default: False. - """ - - entity_id: int - content: str - entity_type: Union[Unset, CreateMessageEntityType] = CreateMessageEntityType.DISCUSSION - files: Union[Unset, list["CreateMessageFilesItem"]] = UNSET - buttons: Union[Unset, list[list["Button"]]] = UNSET - parent_message_id: Union[None, Unset, int] = UNSET - skip_invite_mentions: Union[Unset, bool] = False - link_preview: Union[Unset, bool] = False - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - entity_id = self.entity_id - - content = self.content - - entity_type: Union[Unset, str] = UNSET - if not isinstance(self.entity_type, Unset): - entity_type = self.entity_type.value - - files: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.files, Unset): - files = [] - for files_item_data in self.files: - files_item = files_item_data.to_dict() - files.append(files_item) - - buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET - if not isinstance(self.buttons, Unset): - buttons = [] - for componentsschemas_buttons_item_data in self.buttons: - componentsschemas_buttons_item = [] - for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: - componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - parent_message_id: Union[None, Unset, int] - if isinstance(self.parent_message_id, Unset): - parent_message_id = UNSET - else: - parent_message_id = self.parent_message_id - - skip_invite_mentions = self.skip_invite_mentions - - link_preview = self.link_preview - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "entity_id": entity_id, - "content": content, - } - ) - if entity_type is not UNSET: - field_dict["entity_type"] = entity_type - if files is not UNSET: - field_dict["files"] = files - if buttons is not UNSET: - field_dict["buttons"] = buttons - if parent_message_id is not UNSET: - field_dict["parent_message_id"] = parent_message_id - if skip_invite_mentions is not UNSET: - field_dict["skip_invite_mentions"] = skip_invite_mentions - if link_preview is not UNSET: - field_dict["link_preview"] = link_preview - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.button import Button - from ..models.create_message_files_item import CreateMessageFilesItem - - d = src_dict.copy() - entity_id = d.pop("entity_id") - - content = d.pop("content") - - _entity_type = d.pop("entity_type", UNSET) - entity_type: Union[Unset, CreateMessageEntityType] - if isinstance(_entity_type, Unset): - entity_type = UNSET - else: - entity_type = CreateMessageEntityType(_entity_type) - - files = [] - _files = d.pop("files", UNSET) - for files_item_data in _files or []: - files_item = CreateMessageFilesItem.from_dict(files_item_data) - - files.append(files_item) - - buttons = [] - _buttons = d.pop("buttons", UNSET) - for componentsschemas_buttons_item_data in _buttons or []: - componentsschemas_buttons_item = [] - _componentsschemas_buttons_item = componentsschemas_buttons_item_data - for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: - componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) - - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) - - skip_invite_mentions = d.pop("skip_invite_mentions", UNSET) - - link_preview = d.pop("link_preview", UNSET) - - create_message = cls( - entity_id=entity_id, - content=content, - entity_type=entity_type, - files=files, - buttons=buttons, - parent_message_id=parent_message_id, - skip_invite_mentions=skip_invite_mentions, - link_preview=link_preview, - ) - - create_message.additional_properties = d - return create_message - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py deleted file mode 100644 index a8960fe..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_body.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_message import CreateMessage - - -T = TypeVar("T", bound="CreateMessageBody") - - -@_attrs_define -class CreateMessageBody: - """ - Attributes: - message (Union[Unset, CreateMessage]): - """ - - message: Union[Unset, "CreateMessage"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - message: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.message, Unset): - message = self.message.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if message is not UNSET: - field_dict["message"] = message - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_message import CreateMessage - - d = src_dict.copy() - _message = d.pop("message", UNSET) - message: Union[Unset, CreateMessage] - if isinstance(_message, Unset): - message = UNSET - else: - message = CreateMessage.from_dict(_message) - - create_message_body = cls( - message=message, - ) - - create_message_body.additional_properties = d - return create_message_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py deleted file mode 100644 index 067c6f4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_entity_type.py +++ /dev/null @@ -1,10 +0,0 @@ -from enum import Enum - - -class CreateMessageEntityType(str, Enum): - DISCUSSION = "discussion" - THREAD = "thread" - USER = "user" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py deleted file mode 100644 index a7c8ee3..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item.py +++ /dev/null @@ -1,84 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.create_message_files_item_file_type import CreateMessageFilesItemFileType - -T = TypeVar("T", bound="CreateMessageFilesItem") - - -@_attrs_define -class CreateMessageFilesItem: - """ - Attributes: - key (str): - name (str): - file_type (CreateMessageFilesItemFileType): - size (int): - """ - - key: str - name: str - file_type: CreateMessageFilesItemFileType - size: int - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - name = self.name - - file_type = self.file_type.value - - size = self.size - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "key": key, - "name": name, - "file_type": file_type, - "size": size, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - key = d.pop("key") - - name = d.pop("name") - - file_type = CreateMessageFilesItemFileType(d.pop("file_type")) - - size = d.pop("size") - - create_message_files_item = cls( - key=key, - name=name, - file_type=file_type, - size=size, - ) - - create_message_files_item.additional_properties = d - return create_message_files_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py deleted file mode 100644 index 89889f9..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class CreateMessageFilesItemFileType(str, Enum): - FILE = "file" - IMAGE = "image" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py deleted file mode 100644 index b016d4c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_message_response_201.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="CreateMessageResponse201") - - -@_attrs_define -class CreateMessageResponse201: - """ - Attributes: - data (Union[Unset, Message]): - """ - - data: Union[Unset, "Message"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Message] - if isinstance(_data, Unset): - data = UNSET - else: - data = Message.from_dict(_data) - - create_message_response_201 = cls( - data=data, - ) - - create_message_response_201.additional_properties = d - return create_message_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py deleted file mode 100644 index 15fd0b4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_thread_response_200_data import CreateThreadResponse200Data - - -T = TypeVar("T", bound="CreateThreadResponse200") - - -@_attrs_define -class CreateThreadResponse200: - """ - Attributes: - data (Union[Unset, CreateThreadResponse200Data]): - """ - - data: Union[Unset, "CreateThreadResponse200Data"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_thread_response_200_data import CreateThreadResponse200Data - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, CreateThreadResponse200Data] - if isinstance(_data, Unset): - data = UNSET - else: - data = CreateThreadResponse200Data.from_dict(_data) - - create_thread_response_200 = cls( - data=data, - ) - - create_thread_response_200.additional_properties = d - return create_thread_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py deleted file mode 100644 index 93b7457..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py +++ /dev/null @@ -1,104 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateThreadResponse200Data") - - -@_attrs_define -class CreateThreadResponse200Data: - """ - Attributes: - id (Union[Unset, int]): Идентификатор созданного треда. - chat_id (Union[Unset, int]): Идентификатор чата треда. - message_id (Union[Unset, int]): Идентификатор сообщения, к которому был создан тред. - message_chat_id (Union[Unset, int]): Идентификатор чата сообщения. - updated_at (Union[Unset, datetime.datetime]): Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM- - DDThh:mm:ss.sssZ. - """ - - id: Union[Unset, int] = UNSET - chat_id: Union[Unset, int] = UNSET - message_id: Union[Unset, int] = UNSET - message_chat_id: Union[Unset, int] = UNSET - updated_at: Union[Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - chat_id = self.chat_id - - message_id = self.message_id - - message_chat_id = self.message_chat_id - - updated_at: Union[Unset, str] = UNSET - if not isinstance(self.updated_at, Unset): - updated_at = self.updated_at.isoformat() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if chat_id is not UNSET: - field_dict["chat_id"] = chat_id - if message_id is not UNSET: - field_dict["message_id"] = message_id - if message_chat_id is not UNSET: - field_dict["message_chat_id"] = message_chat_id - if updated_at is not UNSET: - field_dict["updated_at"] = updated_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - chat_id = d.pop("chat_id", UNSET) - - message_id = d.pop("message_id", UNSET) - - message_chat_id = d.pop("message_chat_id", UNSET) - - _updated_at = d.pop("updated_at", UNSET) - updated_at: Union[Unset, datetime.datetime] - if isinstance(_updated_at, Unset): - updated_at = UNSET - else: - updated_at = isoparse(_updated_at) - - create_thread_response_200_data = cls( - id=id, - chat_id=chat_id, - message_id=message_id, - message_chat_id=message_chat_id, - updated_at=updated_at, - ) - - create_thread_response_200_data.additional_properties = d - return create_thread_response_200_data - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py deleted file mode 100644 index 100dc9c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse400") - - -@_attrs_define -class DeleteMessageReactionsResponse400: - """ - Attributes: - errors (Union[Unset, list['DeleteMessageReactionsResponse400ErrorsItem']]): Список ошибок в запросе. - """ - - errors: Union[Unset, list["DeleteMessageReactionsResponse400ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_400_errors_item import ( - DeleteMessageReactionsResponse400ErrorsItem, - ) - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = DeleteMessageReactionsResponse400ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - delete_message_reactions_response_400 = cls( - errors=errors, - ) - - delete_message_reactions_response_400.additional_properties = d - return delete_message_reactions_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py deleted file mode 100644 index 4a61277..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py +++ /dev/null @@ -1,111 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_400_errors_item_payload import ( - DeleteMessageReactionsResponse400ErrorsItemPayload, - ) - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItem") - - -@_attrs_define -class DeleteMessageReactionsResponse400ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. - value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. - message (Union[Unset, str]): Текстовое описание ошибки. - code (Union[Unset, str]): Внутренний код ошибки. - payload (Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "DeleteMessageReactionsResponse400ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_400_errors_item_payload import ( - DeleteMessageReactionsResponse400ErrorsItemPayload, - ) - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = DeleteMessageReactionsResponse400ErrorsItemPayload.from_dict(_payload) - - delete_message_reactions_response_400_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - delete_message_reactions_response_400_errors_item.additional_properties = d - return delete_message_reactions_response_400_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py deleted file mode 100644 index d3d26c9..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItemPayload") - - -@_attrs_define -class DeleteMessageReactionsResponse400ErrorsItemPayload: - """Дополнительная информация об ошибке.""" - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - delete_message_reactions_response_400_errors_item_payload = cls() - - delete_message_reactions_response_400_errors_item_payload.additional_properties = d - return delete_message_reactions_response_400_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py deleted file mode 100644 index 9f918a0..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse404") - - -@_attrs_define -class DeleteMessageReactionsResponse404: - """ - Attributes: - errors (Union[Unset, list['DeleteMessageReactionsResponse404ErrorsItem']]): Список ошибок. - """ - - errors: Union[Unset, list["DeleteMessageReactionsResponse404ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_404_errors_item import ( - DeleteMessageReactionsResponse404ErrorsItem, - ) - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = DeleteMessageReactionsResponse404ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - delete_message_reactions_response_404 = cls( - errors=errors, - ) - - delete_message_reactions_response_404.additional_properties = d - return delete_message_reactions_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py deleted file mode 100644 index 849db9d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py +++ /dev/null @@ -1,111 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_404_errors_item_payload import ( - DeleteMessageReactionsResponse404ErrorsItemPayload, - ) - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItem") - - -@_attrs_define -class DeleteMessageReactionsResponse404ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "DeleteMessageReactionsResponse404ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_404_errors_item_payload import ( - DeleteMessageReactionsResponse404ErrorsItemPayload, - ) - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = DeleteMessageReactionsResponse404ErrorsItemPayload.from_dict(_payload) - - delete_message_reactions_response_404_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - delete_message_reactions_response_404_errors_item.additional_properties = d - return delete_message_reactions_response_404_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py deleted file mode 100644 index f2fa5b5..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItemPayload") - - -@_attrs_define -class DeleteMessageReactionsResponse404ErrorsItemPayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - delete_message_reactions_response_404_errors_item_payload = cls() - - delete_message_reactions_response_404_errors_item_payload.additional_properties = d - return delete_message_reactions_response_404_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py deleted file mode 100644 index aef4bc1..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/direct_response.py +++ /dev/null @@ -1,195 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DirectResponse") - - -@_attrs_define -class DirectResponse: - """ - Attributes: - content_disposition (Union[Unset, str]): - acl (Union[Unset, str]): - policy (Union[Unset, str]): - x_amz_credential (Union[Unset, str]): - x_amz_algorithm (Union[Unset, str]): - x_amz_date (Union[Unset, str]): - x_amz_signature (Union[Unset, str]): - key (Union[Unset, str]): - file (Union[Unset, str]): - """ - - content_disposition: Union[Unset, str] = UNSET - acl: Union[Unset, str] = UNSET - policy: Union[Unset, str] = UNSET - x_amz_credential: Union[Unset, str] = UNSET - x_amz_algorithm: Union[Unset, str] = UNSET - x_amz_date: Union[Unset, str] = UNSET - x_amz_signature: Union[Unset, str] = UNSET - key: Union[Unset, str] = UNSET - file: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - content_disposition = self.content_disposition - - acl = self.acl - - policy = self.policy - - x_amz_credential = self.x_amz_credential - - x_amz_algorithm = self.x_amz_algorithm - - x_amz_date = self.x_amz_date - - x_amz_signature = self.x_amz_signature - - key = self.key - - file = self.file - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if content_disposition is not UNSET: - field_dict["Content-Disposition"] = content_disposition - if acl is not UNSET: - field_dict["acl"] = acl - if policy is not UNSET: - field_dict["policy"] = policy - if x_amz_credential is not UNSET: - field_dict["x-amz-credential"] = x_amz_credential - if x_amz_algorithm is not UNSET: - field_dict["x-amz-algorithm"] = x_amz_algorithm - if x_amz_date is not UNSET: - field_dict["x-amz-date"] = x_amz_date - if x_amz_signature is not UNSET: - field_dict["x-amz-signature"] = x_amz_signature - if key is not UNSET: - field_dict["key"] = key - if file is not UNSET: - field_dict["file"] = file - - return field_dict - - def to_multipart(self) -> dict[str, Any]: - content_disposition = ( - self.content_disposition - if isinstance(self.content_disposition, Unset) - else (None, str(self.content_disposition).encode(), "text/plain") - ) - - acl = self.acl if isinstance(self.acl, Unset) else (None, str(self.acl).encode(), "text/plain") - - policy = self.policy if isinstance(self.policy, Unset) else (None, str(self.policy).encode(), "text/plain") - - x_amz_credential = ( - self.x_amz_credential - if isinstance(self.x_amz_credential, Unset) - else (None, str(self.x_amz_credential).encode(), "text/plain") - ) - - x_amz_algorithm = ( - self.x_amz_algorithm - if isinstance(self.x_amz_algorithm, Unset) - else (None, str(self.x_amz_algorithm).encode(), "text/plain") - ) - - x_amz_date = ( - self.x_amz_date - if isinstance(self.x_amz_date, Unset) - else (None, str(self.x_amz_date).encode(), "text/plain") - ) - - x_amz_signature = ( - self.x_amz_signature - if isinstance(self.x_amz_signature, Unset) - else (None, str(self.x_amz_signature).encode(), "text/plain") - ) - - key = self.key if isinstance(self.key, Unset) else (None, str(self.key).encode(), "text/plain") - - file = self.file if isinstance(self.file, Unset) else (None, str(self.file).encode(), "text/plain") - - field_dict: dict[str, Any] = {} - for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - - field_dict.update({}) - if content_disposition is not UNSET: - field_dict["Content-Disposition"] = content_disposition - if acl is not UNSET: - field_dict["acl"] = acl - if policy is not UNSET: - field_dict["policy"] = policy - if x_amz_credential is not UNSET: - field_dict["x-amz-credential"] = x_amz_credential - if x_amz_algorithm is not UNSET: - field_dict["x-amz-algorithm"] = x_amz_algorithm - if x_amz_date is not UNSET: - field_dict["x-amz-date"] = x_amz_date - if x_amz_signature is not UNSET: - field_dict["x-amz-signature"] = x_amz_signature - if key is not UNSET: - field_dict["key"] = key - if file is not UNSET: - field_dict["file"] = file - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - content_disposition = d.pop("Content-Disposition", UNSET) - - acl = d.pop("acl", UNSET) - - policy = d.pop("policy", UNSET) - - x_amz_credential = d.pop("x-amz-credential", UNSET) - - x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) - - x_amz_date = d.pop("x-amz-date", UNSET) - - x_amz_signature = d.pop("x-amz-signature", UNSET) - - key = d.pop("key", UNSET) - - file = d.pop("file", UNSET) - - direct_response = cls( - content_disposition=content_disposition, - acl=acl, - policy=policy, - x_amz_credential=x_amz_credential, - x_amz_algorithm=x_amz_algorithm, - x_amz_date=x_amz_date, - x_amz_signature=x_amz_signature, - key=key, - file=file, - ) - - direct_response.additional_properties = d - return direct_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py deleted file mode 100644 index 8e6439d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages.py +++ /dev/null @@ -1,113 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem - from ..models.edit_messages_files import EditMessagesFiles - - -T = TypeVar("T", bound="EditMessages") - - -@_attrs_define -class EditMessages: - """Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Attributes: - content (Union[Unset, str]): Текст сообщения Default: 'Текст сообщения'. - files (Union[Unset, EditMessagesFiles]): - buttons (Union[Unset, list[list['EditMessagesButtonsItemItem']]]): Массив строк, каждая из которых представлена - массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в - статье. Для удаления кнопок у сообщения пришлите пустой массив. - """ - - content: Union[Unset, str] = "Текст сообщения" - files: Union[Unset, "EditMessagesFiles"] = UNSET - buttons: Union[Unset, list[list["EditMessagesButtonsItemItem"]]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - content = self.content - - files: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.files, Unset): - files = self.files.to_dict() - - buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET - if not isinstance(self.buttons, Unset): - buttons = [] - for buttons_item_data in self.buttons: - buttons_item = [] - for buttons_item_item_data in buttons_item_data: - buttons_item_item = buttons_item_item_data.to_dict() - buttons_item.append(buttons_item_item) - - buttons.append(buttons_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if content is not UNSET: - field_dict["content"] = content - if files is not UNSET: - field_dict["files"] = files - if buttons is not UNSET: - field_dict["buttons"] = buttons - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem - from ..models.edit_messages_files import EditMessagesFiles - - d = src_dict.copy() - content = d.pop("content", UNSET) - - _files = d.pop("files", UNSET) - files: Union[Unset, EditMessagesFiles] - if isinstance(_files, Unset): - files = UNSET - else: - files = EditMessagesFiles.from_dict(_files) - - buttons = [] - _buttons = d.pop("buttons", UNSET) - for buttons_item_data in _buttons or []: - buttons_item = [] - _buttons_item = buttons_item_data - for buttons_item_item_data in _buttons_item: - buttons_item_item = EditMessagesButtonsItemItem.from_dict(buttons_item_item_data) - - buttons_item.append(buttons_item_item) - - buttons.append(buttons_item) - - edit_messages = cls( - content=content, - files=files, - buttons=buttons, - ) - - edit_messages.additional_properties = d - return edit_messages - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py deleted file mode 100644 index 22494f8..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="EditMessagesButtonsItemItem") - - -@_attrs_define -class EditMessagesButtonsItemItem: - """ - Attributes: - text (Union[Unset, str]): Текст, отображаемый на кнопке пользователю - url (Union[Unset, str]): Ссылка, которая будет открыта по нажатию кнопки - data (Union[Unset, str]): Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки - """ - - text: Union[Unset, str] = UNSET - url: Union[Unset, str] = UNSET - data: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - text = self.text - - url = self.url - - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if text is not UNSET: - field_dict["text"] = text - if url is not UNSET: - field_dict["url"] = url - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - text = d.pop("text", UNSET) - - url = d.pop("url", UNSET) - - data = d.pop("data", UNSET) - - edit_messages_buttons_item_item = cls( - text=text, - url=url, - data=data, - ) - - edit_messages_buttons_item_item.additional_properties = d - return edit_messages_buttons_item_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py deleted file mode 100644 index f42b7bb..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files.py +++ /dev/null @@ -1,95 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.edit_messages_files_file_type import EditMessagesFilesFileType -from ..types import UNSET, Unset - -T = TypeVar("T", bound="EditMessagesFiles") - - -@_attrs_define -class EditMessagesFiles: - """ - Attributes: - key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении - должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе - с расширением) - file_type (Union[Unset, EditMessagesFilesFileType]): - size (Union[Unset, int]): Размер файла в байтах, отображаемый пользователю Default: 1234. - """ - - key: Union[Unset, str] = UNSET - name: Union[Unset, str] = UNSET - file_type: Union[Unset, EditMessagesFilesFileType] = UNSET - size: Union[Unset, int] = 1234 - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - name = self.name - - file_type: Union[Unset, str] = UNSET - if not isinstance(self.file_type, Unset): - file_type = self.file_type.value - - size = self.size - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if name is not UNSET: - field_dict["name"] = name - if file_type is not UNSET: - field_dict["file_type"] = file_type - if size is not UNSET: - field_dict["size"] = size - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - key = d.pop("key", UNSET) - - name = d.pop("name", UNSET) - - _file_type = d.pop("file_type", UNSET) - file_type: Union[Unset, EditMessagesFilesFileType] - if isinstance(_file_type, Unset): - file_type = UNSET - else: - file_type = EditMessagesFilesFileType(_file_type) - - size = d.pop("size", UNSET) - - edit_messages_files = cls( - key=key, - name=name, - file_type=file_type, - size=size, - ) - - edit_messages_files.additional_properties = d - return edit_messages_files - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py deleted file mode 100644 index a78a223..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class EditMessagesFilesFileType(str, Enum): - FILE = "file" - IMAGE = "image" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py deleted file mode 100644 index 9011165..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/employee.py +++ /dev/null @@ -1,275 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - from ..models.status_type_0 import StatusType0 - - -T = TypeVar("T", bound="Employee") - - -@_attrs_define -class Employee: - """ - Attributes: - id (Union[Unset, int]): Идентификатор пользователя Example: 1. - first_name (Union[Unset, str]): Имя - last_name (Union[Unset, str]): Фамилия - nickname (Union[Unset, str]): Имя пользователя - email (Union[Unset, str]): Электронная почта - phone_number (Union[Unset, str]): Телефон - department (Union[Unset, str]): Департамент - role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является - деактивированным. - invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) - list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику - custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника - bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) - user_status (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. - title (Union[Unset, str]): Должность - created_at (Union[Unset, datetime.datetime]): Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone (Union[Unset, str]): Часовой пояс пользователя - image_url (Union[None, Unset, str]): Ссылка на скачивание аватарки - """ - - id: Union[Unset, int] = UNSET - first_name: Union[Unset, str] = UNSET - last_name: Union[Unset, str] = UNSET - nickname: Union[Unset, str] = UNSET - email: Union[Unset, str] = UNSET - phone_number: Union[Unset, str] = UNSET - department: Union[Unset, str] = UNSET - role: Union[Unset, str] = UNSET - suspended: Union[Unset, bool] = UNSET - invite_status: Union[Unset, str] = UNSET - list_tags: Union[Unset, list[str]] = UNSET - custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET - bot: Union[Unset, bool] = UNSET - user_status: Union["StatusType0", None, Unset] = UNSET - title: Union[Unset, str] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - time_zone: Union[Unset, str] = UNSET - image_url: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.status_type_0 import StatusType0 - - id = self.id - - first_name = self.first_name - - last_name = self.last_name - - nickname = self.nickname - - email = self.email - - phone_number = self.phone_number - - department = self.department - - role = self.role - - suspended = self.suspended - - invite_status = self.invite_status - - list_tags: Union[Unset, list[str]] = UNSET - if not isinstance(self.list_tags, Unset): - list_tags = self.list_tags - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - bot = self.bot - - user_status: Union[None, Unset, dict[str, Any]] - if isinstance(self.user_status, Unset): - user_status = UNSET - elif isinstance(self.user_status, StatusType0): - user_status = self.user_status.to_dict() - else: - user_status = self.user_status - - title = self.title - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - time_zone = self.time_zone - - image_url: Union[None, Unset, str] - if isinstance(self.image_url, Unset): - image_url = UNSET - else: - image_url = self.image_url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if first_name is not UNSET: - field_dict["first_name"] = first_name - if last_name is not UNSET: - field_dict["last_name"] = last_name - if nickname is not UNSET: - field_dict["nickname"] = nickname - if email is not UNSET: - field_dict["email"] = email - if phone_number is not UNSET: - field_dict["phone_number"] = phone_number - if department is not UNSET: - field_dict["department"] = department - if role is not UNSET: - field_dict["role"] = role - if suspended is not UNSET: - field_dict["suspended"] = suspended - if invite_status is not UNSET: - field_dict["invite_status"] = invite_status - if list_tags is not UNSET: - field_dict["list_tags"] = list_tags - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - if bot is not UNSET: - field_dict["bot"] = bot - if user_status is not UNSET: - field_dict["user_status"] = user_status - if title is not UNSET: - field_dict["title"] = title - if created_at is not UNSET: - field_dict["created_at"] = created_at - if time_zone is not UNSET: - field_dict["time_zone"] = time_zone - if image_url is not UNSET: - field_dict["image_url"] = image_url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - from ..models.status_type_0 import StatusType0 - - d = src_dict.copy() - id = d.pop("id", UNSET) - - first_name = d.pop("first_name", UNSET) - - last_name = d.pop("last_name", UNSET) - - nickname = d.pop("nickname", UNSET) - - email = d.pop("email", UNSET) - - phone_number = d.pop("phone_number", UNSET) - - department = d.pop("department", UNSET) - - role = d.pop("role", UNSET) - - suspended = d.pop("suspended", UNSET) - - invite_status = d.pop("invite_status", UNSET) - - list_tags = cast(list[str], d.pop("list_tags", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - bot = d.pop("bot", UNSET) - - def _parse_user_status(data: object) -> Union["StatusType0", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - componentsschemas_status_type_0 = StatusType0.from_dict(data) - - return componentsschemas_status_type_0 - except: # noqa: E722 - pass - return cast(Union["StatusType0", None, Unset], data) - - user_status = _parse_user_status(d.pop("user_status", UNSET)) - - title = d.pop("title", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - time_zone = d.pop("time_zone", UNSET) - - def _parse_image_url(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - image_url = _parse_image_url(d.pop("image_url", UNSET)) - - employee = cls( - id=id, - first_name=first_name, - last_name=last_name, - nickname=nickname, - email=email, - phone_number=phone_number, - department=department, - role=role, - suspended=suspended, - invite_status=invite_status, - list_tags=list_tags, - custom_properties=custom_properties, - bot=bot, - user_status=user_status, - title=title, - created_at=created_at, - time_zone=time_zone, - image_url=image_url, - ) - - employee.additional_properties = d - return employee - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py deleted file mode 100644 index e9e73d2..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error_payload import ErrorPayload - - -T = TypeVar("T", bound="Error") - - -@_attrs_define -class Error: - """ - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, ErrorPayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "ErrorPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error_payload import ErrorPayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, ErrorPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = ErrorPayload.from_dict(_payload) - - error = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - error.additional_properties = d - return error - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py deleted file mode 100644 index 9133249..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/error_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="ErrorPayload") - - -@_attrs_define -class ErrorPayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error_payload = cls() - - error_payload.additional_properties = d - return error_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py deleted file mode 100644 index 52b0dee..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code.py +++ /dev/null @@ -1,108 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.errors_code_payload import ErrorsCodePayload - - -T = TypeVar("T", bound="ErrorsCode") - - -@_attrs_define -class ErrorsCode: - """Bad Request - - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, ErrorsCodePayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "ErrorsCodePayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.errors_code_payload import ErrorsCodePayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, ErrorsCodePayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = ErrorsCodePayload.from_dict(_payload) - - errors_code = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - errors_code.additional_properties = d - return errors_code - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py deleted file mode 100644 index 8128de2..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/errors_code_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="ErrorsCodePayload") - - -@_attrs_define -class ErrorsCodePayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - errors_code_payload = cls() - - errors_code_payload.additional_properties = d - return errors_code_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py deleted file mode 100644 index 5bb1dc4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/file_response.py +++ /dev/null @@ -1,130 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="FileResponse") - - -@_attrs_define -class FileResponse: - """ - Attributes: - content_disposition (Union[Unset, str]): - acl (Union[Unset, str]): - policy (Union[Unset, str]): - x_amz_credential (Union[Unset, str]): - x_amz_algorithm (Union[Unset, str]): - x_amz_date (Union[Unset, str]): - x_amz_signature (Union[Unset, str]): - key (Union[Unset, str]): - direct_url (Union[Unset, str]): - """ - - content_disposition: Union[Unset, str] = UNSET - acl: Union[Unset, str] = UNSET - policy: Union[Unset, str] = UNSET - x_amz_credential: Union[Unset, str] = UNSET - x_amz_algorithm: Union[Unset, str] = UNSET - x_amz_date: Union[Unset, str] = UNSET - x_amz_signature: Union[Unset, str] = UNSET - key: Union[Unset, str] = UNSET - direct_url: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - content_disposition = self.content_disposition - - acl = self.acl - - policy = self.policy - - x_amz_credential = self.x_amz_credential - - x_amz_algorithm = self.x_amz_algorithm - - x_amz_date = self.x_amz_date - - x_amz_signature = self.x_amz_signature - - key = self.key - - direct_url = self.direct_url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if content_disposition is not UNSET: - field_dict["Content-Disposition"] = content_disposition - if acl is not UNSET: - field_dict["acl"] = acl - if policy is not UNSET: - field_dict["policy"] = policy - if x_amz_credential is not UNSET: - field_dict["x-amz-credential"] = x_amz_credential - if x_amz_algorithm is not UNSET: - field_dict["x-amz-algorithm"] = x_amz_algorithm - if x_amz_date is not UNSET: - field_dict["x-amz-date"] = x_amz_date - if x_amz_signature is not UNSET: - field_dict["x-amz-signature"] = x_amz_signature - if key is not UNSET: - field_dict["key"] = key - if direct_url is not UNSET: - field_dict["direct_url"] = direct_url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - content_disposition = d.pop("Content-Disposition", UNSET) - - acl = d.pop("acl", UNSET) - - policy = d.pop("policy", UNSET) - - x_amz_credential = d.pop("x-amz-credential", UNSET) - - x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) - - x_amz_date = d.pop("x-amz-date", UNSET) - - x_amz_signature = d.pop("x-amz-signature", UNSET) - - key = d.pop("key", UNSET) - - direct_url = d.pop("direct_url", UNSET) - - file_response = cls( - content_disposition=content_disposition, - acl=acl, - policy=policy, - x_amz_credential=x_amz_credential, - x_amz_algorithm=x_amz_algorithm, - x_amz_date=x_amz_date, - x_amz_signature=x_amz_signature, - key=key, - direct_url=direct_url, - ) - - file_response.additional_properties = d - return file_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py deleted file mode 100644 index 274ed8c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.chat import Chat - - -T = TypeVar("T", bound="GetChatResponse200") - - -@_attrs_define -class GetChatResponse200: - """ - Attributes: - data (Union[Unset, Chat]): Беседа или канал - """ - - data: Union[Unset, "Chat"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.chat import Chat - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Chat] - if isinstance(_data, Unset): - data = UNSET - else: - data = Chat.from_dict(_data) - - get_chat_response_200 = cls( - data=data, - ) - - get_chat_response_200.additional_properties = d - return get_chat_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py deleted file mode 100644 index 6aaf8b1..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chat_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="GetChatResponse404") - - -@_attrs_define -class GetChatResponse404: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - get_chat_response_404 = cls( - errors=errors, - ) - - get_chat_response_404.additional_properties = d - return get_chat_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py deleted file mode 100644 index b76cb4d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_availability.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class GetChatsAvailability(str, Enum): - IS_MEMBER = "is_member" - PUBLIC = "public" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py deleted file mode 100644 index 3917a9f..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.chat import Chat - - -T = TypeVar("T", bound="GetChatsResponse200") - - -@_attrs_define -class GetChatsResponse200: - """ - Attributes: - data (Union[Unset, list['Chat']]): - """ - - data: Union[Unset, list["Chat"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.chat import Chat - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Chat.from_dict(data_item_data) - - data.append(data_item) - - get_chats_response_200 = cls( - data=data, - ) - - get_chats_response_200.additional_properties = d - return get_chats_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py deleted file mode 100644 index 005a6a3..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_400.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.errors_code import ErrorsCode - - -T = TypeVar("T", bound="GetChatsResponse400") - - -@_attrs_define -class GetChatsResponse400: - """ - Attributes: - errors (Union[Unset, ErrorsCode]): Bad Request - """ - - errors: Union[Unset, "ErrorsCode"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.errors, Unset): - errors = self.errors.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.errors_code import ErrorsCode - - d = src_dict.copy() - _errors = d.pop("errors", UNSET) - errors: Union[Unset, ErrorsCode] - if isinstance(_errors, Unset): - errors = UNSET - else: - errors = ErrorsCode.from_dict(_errors) - - get_chats_response_400 = cls( - errors=errors, - ) - - get_chats_response_400.additional_properties = d - return get_chats_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py deleted file mode 100644 index 1553a65..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="GetChatsResponse404") - - -@_attrs_define -class GetChatsResponse404: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - get_chats_response_404 = cls( - errors=errors, - ) - - get_chats_response_404.additional_properties = d - return get_chats_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py deleted file mode 100644 index 5248609..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_response_422.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="GetChatsResponse422") - - -@_attrs_define -class GetChatsResponse422: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - get_chats_response_422 = cls( - errors=errors, - ) - - get_chats_response_422.additional_properties = d - return get_chats_response_422 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py deleted file mode 100644 index 0de410c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_chats_sortid.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class GetChatsSortid(str, Enum): - ASC = "asc" - DESC = "desc" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py deleted file mode 100644 index 93ea91d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.query_common_methods import QueryCommonMethods - - -T = TypeVar("T", bound="GetCommonMethodsResponse200") - - -@_attrs_define -class GetCommonMethodsResponse200: - """ - Attributes: - data (Union[Unset, list['QueryCommonMethods']]): - """ - - data: Union[Unset, list["QueryCommonMethods"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.query_common_methods import QueryCommonMethods - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = QueryCommonMethods.from_dict(data_item_data) - - data.append(data_item) - - get_common_methods_response_200 = cls( - data=data, - ) - - get_common_methods_response_200.additional_properties = d - return get_common_methods_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py deleted file mode 100644 index b970ea8..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employee_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.employee import Employee - - -T = TypeVar("T", bound="GetEmployeeResponse200") - - -@_attrs_define -class GetEmployeeResponse200: - """ - Attributes: - data (Union[Unset, Employee]): - """ - - data: Union[Unset, "Employee"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.employee import Employee - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Employee] - if isinstance(_data, Unset): - data = UNSET - else: - data = Employee.from_dict(_data) - - get_employee_response_200 = cls( - data=data, - ) - - get_employee_response_200.additional_properties = d - return get_employee_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py deleted file mode 100644 index 978802c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_employees_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.employee import Employee - - -T = TypeVar("T", bound="GetEmployeesResponse200") - - -@_attrs_define -class GetEmployeesResponse200: - """ - Attributes: - data (Union[Unset, list['Employee']]): - """ - - data: Union[Unset, list["Employee"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.employee import Employee - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Employee.from_dict(data_item_data) - - data.append(data_item) - - get_employees_response_200 = cls( - data=data, - ) - - get_employees_response_200.additional_properties = d - return get_employees_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py deleted file mode 100644 index 52837e1..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="GetListMessageResponse200") - - -@_attrs_define -class GetListMessageResponse200: - """ - Attributes: - data (Union[Unset, list['Message']]): - """ - - data: Union[Unset, list["Message"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Message.from_dict(data_item_data) - - data.append(data_item) - - get_list_message_response_200 = cls( - data=data, - ) - - get_list_message_response_200.additional_properties = d - return get_list_message_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py deleted file mode 100644 index eaa7bb5..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py +++ /dev/null @@ -1,68 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="GetMessageReactionsBody") - - -@_attrs_define -class GetMessageReactionsBody: - """ - Attributes: - per (Union[Unset, int]): Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - Default: 50. - page (Union[Unset, int]): Номер страницы выборки (по умолчанию 1). Default: 1. - """ - - per: Union[Unset, int] = 50 - page: Union[Unset, int] = 1 - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - per = self.per - - page = self.page - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if per is not UNSET: - field_dict["per"] = per - if page is not UNSET: - field_dict["page"] = page - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - per = d.pop("per", UNSET) - - page = d.pop("page", UNSET) - - get_message_reactions_body = cls( - per=per, - page=page, - ) - - get_message_reactions_body.additional_properties = d - return get_message_reactions_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py deleted file mode 100644 index 3c50c79..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.reaction import Reaction - - -T = TypeVar("T", bound="GetMessageReactionsResponse200") - - -@_attrs_define -class GetMessageReactionsResponse200: - """ - Attributes: - data (Union[Unset, list['Reaction']]): - """ - - data: Union[Unset, list["Reaction"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.reaction import Reaction - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Reaction.from_dict(data_item_data) - - data.append(data_item) - - get_message_reactions_response_200 = cls( - data=data, - ) - - get_message_reactions_response_200.additional_properties = d - return get_message_reactions_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py deleted file mode 100644 index 677295d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_message_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="GetMessageResponse200") - - -@_attrs_define -class GetMessageResponse200: - """ - Attributes: - data (Union[Unset, Message]): - """ - - data: Union[Unset, "Message"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Message] - if isinstance(_data, Unset): - data = UNSET - else: - data = Message.from_dict(_data) - - get_message_response_200 = cls( - data=data, - ) - - get_message_response_200.additional_properties = d - return get_message_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py deleted file mode 100644 index 7e93886..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_status_response_200.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.status_type_0 import StatusType0 - - -T = TypeVar("T", bound="GetStatusResponse200") - - -@_attrs_define -class GetStatusResponse200: - """ - Attributes: - data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. - """ - - data: Union["StatusType0", None, Unset] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.status_type_0 import StatusType0 - - data: Union[None, Unset, dict[str, Any]] - if isinstance(self.data, Unset): - data = UNSET - elif isinstance(self.data, StatusType0): - data = self.data.to_dict() - else: - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.status_type_0 import StatusType0 - - d = src_dict.copy() - - def _parse_data(data: object) -> Union["StatusType0", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - componentsschemas_status_type_0 = StatusType0.from_dict(data) - - return componentsschemas_status_type_0 - except: # noqa: E722 - pass - return cast(Union["StatusType0", None, Unset], data) - - data = _parse_data(d.pop("data", UNSET)) - - get_status_response_200 = cls( - data=data, - ) - - get_status_response_200.additional_properties = d - return get_status_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py deleted file mode 100644 index 188f734..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.tag import Tag - - -T = TypeVar("T", bound="GetTagResponse200") - - -@_attrs_define -class GetTagResponse200: - """ - Attributes: - data (Union[Unset, Tag]): Для получения тега вам необходимо знать его id и указать его в URL запроса. - """ - - data: Union[Unset, "Tag"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.tag import Tag - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Tag] - if isinstance(_data, Unset): - data = UNSET - else: - data = Tag.from_dict(_data) - - get_tag_response_200 = cls( - data=data, - ) - - get_tag_response_200.additional_properties = d - return get_tag_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py deleted file mode 100644 index c3c8ead..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem - - -T = TypeVar("T", bound="GetTagResponse404") - - -@_attrs_define -class GetTagResponse404: - """ - Attributes: - errors (Union[Unset, list['GetTagResponse404ErrorsItem']]): Список ошибок. - """ - - errors: Union[Unset, list["GetTagResponse404ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = GetTagResponse404ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - get_tag_response_404 = cls( - errors=errors, - ) - - get_tag_response_404.additional_properties = d - return get_tag_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py deleted file mode 100644 index 18649e6..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload - - -T = TypeVar("T", bound="GetTagResponse404ErrorsItem") - - -@_attrs_define -class GetTagResponse404ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, GetTagResponse404ErrorsItemPayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "GetTagResponse404ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, GetTagResponse404ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = GetTagResponse404ErrorsItemPayload.from_dict(_payload) - - get_tag_response_404_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - get_tag_response_404_errors_item.additional_properties = d - return get_tag_response_404_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py deleted file mode 100644 index b6d7c6c..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="GetTagResponse404ErrorsItemPayload") - - -@_attrs_define -class GetTagResponse404ErrorsItemPayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - get_tag_response_404_errors_item_payload = cls() - - get_tag_response_404_errors_item_payload.additional_properties = d - return get_tag_response_404_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py deleted file mode 100644 index 682b3fa..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.base_employee import BaseEmployee - - -T = TypeVar("T", bound="GetTagsEmployeesResponse200") - - -@_attrs_define -class GetTagsEmployeesResponse200: - """ - Attributes: - data (Union[Unset, list['BaseEmployee']]): - """ - - data: Union[Unset, list["BaseEmployee"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.base_employee import BaseEmployee - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = BaseEmployee.from_dict(data_item_data) - - data.append(data_item) - - get_tags_employees_response_200 = cls( - data=data, - ) - - get_tags_employees_response_200.additional_properties = d - return get_tags_employees_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py deleted file mode 100644 index 1ae18d4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.tag import Tag - - -T = TypeVar("T", bound="GetTagsResponse200") - - -@_attrs_define -class GetTagsResponse200: - """ - Attributes: - data (Union[Unset, list['Tag']]): - """ - - data: Union[Unset, list["Tag"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.tag import Tag - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Tag.from_dict(data_item_data) - - data.append(data_item) - - get_tags_response_200 = cls( - data=data, - ) - - get_tags_response_200.additional_properties = d - return get_tags_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py deleted file mode 100644 index 1865c60..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem - - -T = TypeVar("T", bound="GetTagsResponse400") - - -@_attrs_define -class GetTagsResponse400: - """ - Attributes: - errors (Union[Unset, list['GetTagsResponse400ErrorsItem']]): Список ошибок в запросе. - """ - - errors: Union[Unset, list["GetTagsResponse400ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = GetTagsResponse400ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - get_tags_response_400 = cls( - errors=errors, - ) - - get_tags_response_400.additional_properties = d - return get_tags_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py deleted file mode 100644 index bd7859d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload - - -T = TypeVar("T", bound="GetTagsResponse400ErrorsItem") - - -@_attrs_define -class GetTagsResponse400ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. - value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. - message (Union[Unset, str]): Текстовое описание ошибки. - code (Union[Unset, str]): Внутренний код ошибки. - payload (Union[Unset, GetTagsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "GetTagsResponse400ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, GetTagsResponse400ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = GetTagsResponse400ErrorsItemPayload.from_dict(_payload) - - get_tags_response_400_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - get_tags_response_400_errors_item.additional_properties = d - return get_tags_response_400_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py deleted file mode 100644 index 2e1d941..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="GetTagsResponse400ErrorsItemPayload") - - -@_attrs_define -class GetTagsResponse400ErrorsItemPayload: - """Дополнительная информация об ошибке.""" - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - get_tags_response_400_errors_item_payload = cls() - - get_tags_response_400_errors_item_payload.additional_properties = d - return get_tags_response_400_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py deleted file mode 100644 index bb01030..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message.py +++ /dev/null @@ -1,272 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..models.message_entity_type import MessageEntityType -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.button import Button - from ..models.message_files_item import MessageFilesItem - from ..models.message_forwarding import MessageForwarding - from ..models.message_thread import MessageThread - - -T = TypeVar("T", bound="Message") - - -@_attrs_define -class Message: - """ - Attributes: - entity_type (Union[Unset, MessageEntityType]): Default: MessageEntityType.DISCUSSION. - entity_id (Union[Unset, int]): - content (Union[Unset, str]): - id (Union[Unset, int]): - chat_id (Union[Unset, int]): - user_id (Union[Unset, int]): - created_at (Union[Unset, datetime.datetime]): - files (Union[Unset, list['MessageFilesItem']]): - buttons (Union[Unset, list[list['Button']]]): - thread (Union['MessageThread', None, Unset]): - forwarding (Union['MessageForwarding', None, Unset]): - parent_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому написан ответ. Возвращается как - null, если сообщение не является ответом. - """ - - entity_type: Union[Unset, MessageEntityType] = MessageEntityType.DISCUSSION - entity_id: Union[Unset, int] = UNSET - content: Union[Unset, str] = UNSET - id: Union[Unset, int] = UNSET - chat_id: Union[Unset, int] = UNSET - user_id: Union[Unset, int] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - files: Union[Unset, list["MessageFilesItem"]] = UNSET - buttons: Union[Unset, list[list["Button"]]] = UNSET - thread: Union["MessageThread", None, Unset] = UNSET - forwarding: Union["MessageForwarding", None, Unset] = UNSET - parent_message_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.message_forwarding import MessageForwarding - from ..models.message_thread import MessageThread - - entity_type: Union[Unset, str] = UNSET - if not isinstance(self.entity_type, Unset): - entity_type = self.entity_type.value - - entity_id = self.entity_id - - content = self.content - - id = self.id - - chat_id = self.chat_id - - user_id = self.user_id - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - files: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.files, Unset): - files = [] - for files_item_data in self.files: - files_item = files_item_data.to_dict() - files.append(files_item) - - buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET - if not isinstance(self.buttons, Unset): - buttons = [] - for componentsschemas_buttons_item_data in self.buttons: - componentsschemas_buttons_item = [] - for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: - componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - thread: Union[None, Unset, dict[str, Any]] - if isinstance(self.thread, Unset): - thread = UNSET - elif isinstance(self.thread, MessageThread): - thread = self.thread.to_dict() - else: - thread = self.thread - - forwarding: Union[None, Unset, dict[str, Any]] - if isinstance(self.forwarding, Unset): - forwarding = UNSET - elif isinstance(self.forwarding, MessageForwarding): - forwarding = self.forwarding.to_dict() - else: - forwarding = self.forwarding - - parent_message_id: Union[None, Unset, int] - if isinstance(self.parent_message_id, Unset): - parent_message_id = UNSET - else: - parent_message_id = self.parent_message_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if entity_type is not UNSET: - field_dict["entity_type"] = entity_type - if entity_id is not UNSET: - field_dict["entity_id"] = entity_id - if content is not UNSET: - field_dict["content"] = content - if id is not UNSET: - field_dict["id"] = id - if chat_id is not UNSET: - field_dict["chat_id"] = chat_id - if user_id is not UNSET: - field_dict["user_id"] = user_id - if created_at is not UNSET: - field_dict["created_at"] = created_at - if files is not UNSET: - field_dict["files"] = files - if buttons is not UNSET: - field_dict["buttons"] = buttons - if thread is not UNSET: - field_dict["thread"] = thread - if forwarding is not UNSET: - field_dict["forwarding"] = forwarding - if parent_message_id is not UNSET: - field_dict["parent_message_id"] = parent_message_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.button import Button - from ..models.message_files_item import MessageFilesItem - from ..models.message_forwarding import MessageForwarding - from ..models.message_thread import MessageThread - - d = src_dict.copy() - _entity_type = d.pop("entity_type", UNSET) - entity_type: Union[Unset, MessageEntityType] - if isinstance(_entity_type, Unset): - entity_type = UNSET - else: - entity_type = MessageEntityType(_entity_type) - - entity_id = d.pop("entity_id", UNSET) - - content = d.pop("content", UNSET) - - id = d.pop("id", UNSET) - - chat_id = d.pop("chat_id", UNSET) - - user_id = d.pop("user_id", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - files = [] - _files = d.pop("files", UNSET) - for files_item_data in _files or []: - files_item = MessageFilesItem.from_dict(files_item_data) - - files.append(files_item) - - buttons = [] - _buttons = d.pop("buttons", UNSET) - for componentsschemas_buttons_item_data in _buttons or []: - componentsschemas_buttons_item = [] - _componentsschemas_buttons_item = componentsschemas_buttons_item_data - for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: - componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) - - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - def _parse_thread(data: object) -> Union["MessageThread", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - thread_type_0 = MessageThread.from_dict(data) - - return thread_type_0 - except: # noqa: E722 - pass - return cast(Union["MessageThread", None, Unset], data) - - thread = _parse_thread(d.pop("thread", UNSET)) - - def _parse_forwarding(data: object) -> Union["MessageForwarding", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - forwarding_type_0 = MessageForwarding.from_dict(data) - - return forwarding_type_0 - except: # noqa: E722 - pass - return cast(Union["MessageForwarding", None, Unset], data) - - forwarding = _parse_forwarding(d.pop("forwarding", UNSET)) - - def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) - - message = cls( - entity_type=entity_type, - entity_id=entity_id, - content=content, - id=id, - chat_id=chat_id, - user_id=user_id, - created_at=created_at, - files=files, - buttons=buttons, - thread=thread, - forwarding=forwarding, - parent_message_id=parent_message_id, - ) - - message.additional_properties = d - return message - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py deleted file mode 100644 index e8a126a..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_entity_type.py +++ /dev/null @@ -1,10 +0,0 @@ -from enum import Enum - - -class MessageEntityType(str, Enum): - DISCUSSION = "discussion" - THREAD = "thread" - USER = "user" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py deleted file mode 100644 index 21509d2..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.message_files_item_file_type import MessageFilesItemFileType -from ..types import UNSET, Unset - -T = TypeVar("T", bound="MessageFilesItem") - - -@_attrs_define -class MessageFilesItem: - """ - Attributes: - id (Union[Unset, int]): - key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении - должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе - с расширением) - file_type (Union[Unset, MessageFilesItemFileType]): - url (Union[Unset, str]): Размер файла в байтах, отображаемый пользователю - """ - - id: Union[Unset, int] = UNSET - key: Union[Unset, str] = UNSET - name: Union[Unset, str] = UNSET - file_type: Union[Unset, MessageFilesItemFileType] = UNSET - url: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - key = self.key - - name = self.name - - file_type: Union[Unset, str] = UNSET - if not isinstance(self.file_type, Unset): - file_type = self.file_type.value - - url = self.url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if key is not UNSET: - field_dict["key"] = key - if name is not UNSET: - field_dict["name"] = name - if file_type is not UNSET: - field_dict["file_type"] = file_type - if url is not UNSET: - field_dict["url"] = url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - key = d.pop("key", UNSET) - - name = d.pop("name", UNSET) - - _file_type = d.pop("file_type", UNSET) - file_type: Union[Unset, MessageFilesItemFileType] - if isinstance(_file_type, Unset): - file_type = UNSET - else: - file_type = MessageFilesItemFileType(_file_type) - - url = d.pop("url", UNSET) - - message_files_item = cls( - id=id, - key=key, - name=name, - file_type=file_type, - url=url, - ) - - message_files_item.additional_properties = d - return message_files_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py deleted file mode 100644 index 1e00e5b..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class MessageFilesItemFileType(str, Enum): - FILE = "file" - IMAGE = "image" - - def __str__(self) -> str: - return str(self.value) diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py deleted file mode 100644 index 6ce981d..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_forwarding.py +++ /dev/null @@ -1,153 +0,0 @@ -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="MessageForwarding") - - -@_attrs_define -class MessageForwarding: - """ - Attributes: - original_message_id (Union[Unset, int]): Идентификатор оригинального сообщения - original_chat_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение - author_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение - original_created_at (Union[Unset, int]): Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в - формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id (Union[None, Unset, int]): Идентификатор треда, в котором находится оригинальное сообщение. - Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому был создан тред, в - котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является - комментарием в треде. - original_thread_parent_chat_id (Union[None, Unset, int]): Идентификатор чата сообщения, к которому был создан - тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является - комментарием в треде. - """ - - original_message_id: Union[Unset, int] = UNSET - original_chat_id: Union[Unset, int] = UNSET - author_id: Union[Unset, int] = UNSET - original_created_at: Union[Unset, int] = UNSET - original_thread_id: Union[None, Unset, int] = UNSET - original_thread_message_id: Union[None, Unset, int] = UNSET - original_thread_parent_chat_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - original_message_id = self.original_message_id - - original_chat_id = self.original_chat_id - - author_id = self.author_id - - original_created_at = self.original_created_at - - original_thread_id: Union[None, Unset, int] - if isinstance(self.original_thread_id, Unset): - original_thread_id = UNSET - else: - original_thread_id = self.original_thread_id - - original_thread_message_id: Union[None, Unset, int] - if isinstance(self.original_thread_message_id, Unset): - original_thread_message_id = UNSET - else: - original_thread_message_id = self.original_thread_message_id - - original_thread_parent_chat_id: Union[None, Unset, int] - if isinstance(self.original_thread_parent_chat_id, Unset): - original_thread_parent_chat_id = UNSET - else: - original_thread_parent_chat_id = self.original_thread_parent_chat_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if original_message_id is not UNSET: - field_dict["original_message_id"] = original_message_id - if original_chat_id is not UNSET: - field_dict["original_chat_id"] = original_chat_id - if author_id is not UNSET: - field_dict["author_id"] = author_id - if original_created_at is not UNSET: - field_dict["original_created_at"] = original_created_at - if original_thread_id is not UNSET: - field_dict["original_thread_id"] = original_thread_id - if original_thread_message_id is not UNSET: - field_dict["original_thread_message_id"] = original_thread_message_id - if original_thread_parent_chat_id is not UNSET: - field_dict["original_thread_parent_chat_id"] = original_thread_parent_chat_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - original_message_id = d.pop("original_message_id", UNSET) - - original_chat_id = d.pop("original_chat_id", UNSET) - - author_id = d.pop("author_id", UNSET) - - original_created_at = d.pop("original_created_at", UNSET) - - def _parse_original_thread_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - original_thread_id = _parse_original_thread_id(d.pop("original_thread_id", UNSET)) - - def _parse_original_thread_message_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - original_thread_message_id = _parse_original_thread_message_id(d.pop("original_thread_message_id", UNSET)) - - def _parse_original_thread_parent_chat_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - original_thread_parent_chat_id = _parse_original_thread_parent_chat_id( - d.pop("original_thread_parent_chat_id", UNSET) - ) - - message_forwarding = cls( - original_message_id=original_message_id, - original_chat_id=original_chat_id, - author_id=author_id, - original_created_at=original_created_at, - original_thread_id=original_thread_id, - original_thread_message_id=original_thread_message_id, - original_thread_parent_chat_id=original_thread_parent_chat_id, - ) - - message_forwarding.additional_properties = d - return message_forwarding - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py deleted file mode 100644 index ddd18f0..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/message_thread.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="MessageThread") - - -@_attrs_define -class MessageThread: - """ - Attributes: - id (Union[Unset, int]): - chat_id (Union[Unset, int]): - """ - - id: Union[Unset, int] = UNSET - chat_id: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - chat_id = self.chat_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if chat_id is not UNSET: - field_dict["chat_id"] = chat_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - chat_id = d.pop("chat_id", UNSET) - - message_thread = cls( - id=id, - chat_id=chat_id, - ) - - message_thread.additional_properties = d - return message_thread - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py deleted file mode 100644 index c24e928..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/not_found.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="NotFound") - - -@_attrs_define -class NotFound: - """Объект не найден - - Attributes: - detail (Union[Unset, str]): Описание ошибки Example: Страница не найдена.. - """ - - detail: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - detail = self.detail - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if detail is not UNSET: - field_dict["detail"] = detail - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - detail = d.pop("detail", UNSET) - - not_found = cls( - detail=detail, - ) - - not_found.additional_properties = d - return not_found - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py deleted file mode 100644 index 620f8dc..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py +++ /dev/null @@ -1,69 +0,0 @@ -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMembersToChatsBody") - - -@_attrs_define -class PostMembersToChatsBody: - """ - Attributes: - member_ids (list[int]): Example: [186, 187]. - silent (Union[Unset, bool]): - """ - - member_ids: list[int] - silent: Union[Unset, bool] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - member_ids = self.member_ids - - silent = self.silent - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "member_ids": member_ids, - } - ) - if silent is not UNSET: - field_dict["silent"] = silent - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - member_ids = cast(list[int], d.pop("member_ids")) - - silent = d.pop("silent", UNSET) - - post_members_to_chats_body = cls( - member_ids=member_ids, - silent=silent, - ) - - post_members_to_chats_body.additional_properties = d - return post_members_to_chats_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py deleted file mode 100644 index fffa22a..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="PostMessageReactionsBody") - - -@_attrs_define -class PostMessageReactionsBody: - """ - Attributes: - code (str): Emoji в строковом формате для добавления реакции. - """ - - code: str - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - code = self.code - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "code": code, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - code = d.pop("code") - - post_message_reactions_body = cls( - code=code, - ) - - post_message_reactions_body.additional_properties = d - return post_message_reactions_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py deleted file mode 100644 index 50b0078..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMessageReactionsResponse400") - - -@_attrs_define -class PostMessageReactionsResponse400: - """ - Attributes: - error (Union[Unset, str]): Описание ошибки. - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_message_reactions_response_400 = cls( - error=error, - ) - - post_message_reactions_response_400.additional_properties = d - return post_message_reactions_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py deleted file mode 100644 index cd52780..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMessageReactionsResponse403") - - -@_attrs_define -class PostMessageReactionsResponse403: - """ - Attributes: - error (Union[Unset, str]): Описание ошибки. - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_message_reactions_response_403 = cls( - error=error, - ) - - post_message_reactions_response_403.additional_properties = d - return post_message_reactions_response_403 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py deleted file mode 100644 index 1a26c89..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMessageReactionsResponse404") - - -@_attrs_define -class PostMessageReactionsResponse404: - """ - Attributes: - error (Union[Unset, str]): Сообщение не найдено. - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_message_reactions_response_404 = cls( - error=error, - ) - - post_message_reactions_response_404.additional_properties = d - return post_message_reactions_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py deleted file mode 100644 index 23040f4..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="PostTagsToChatsBody") - - -@_attrs_define -class PostTagsToChatsBody: - """ - Attributes: - group_tag_ids (list[int]): Example: [86, 18]. - """ - - group_tag_ids: list[int] - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - group_tag_ids = self.group_tag_ids - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "group_tag_ids": group_tag_ids, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - group_tag_ids = cast(list[int], d.pop("group_tag_ids")) - - post_tags_to_chats_body = cls( - group_tag_ids=group_tag_ids, - ) - - post_tags_to_chats_body.additional_properties = d - return post_tags_to_chats_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py deleted file mode 100644 index 1abee57..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.post_tasks_body_task import PostTasksBodyTask - - -T = TypeVar("T", bound="PostTasksBody") - - -@_attrs_define -class PostTasksBody: - """ - Attributes: - task (Union[Unset, PostTasksBodyTask]): - """ - - task: Union[Unset, "PostTasksBodyTask"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - task: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.task, Unset): - task = self.task.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if task is not UNSET: - field_dict["task"] = task - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.post_tasks_body_task import PostTasksBodyTask - - d = src_dict.copy() - _task = d.pop("task", UNSET) - task: Union[Unset, PostTasksBodyTask] - if isinstance(_task, Unset): - task = UNSET - else: - task = PostTasksBodyTask.from_dict(_task) - - post_tasks_body = cls( - task=task, - ) - - post_tasks_body.additional_properties = d - return post_tasks_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py deleted file mode 100644 index f85bf85..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task.py +++ /dev/null @@ -1,123 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem - - -T = TypeVar("T", bound="PostTasksBodyTask") - - -@_attrs_define -class PostTasksBodyTask: - """ - Attributes: - kind (str): Тип напоминания (call, meeting, reminder, event, email) - content (str): Описание напоминания - due_at (datetime.datetime): Срок выполнения напоминания (ISO-8601) - priority (Union[Unset, int]): Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей - custom_properties (Union[Unset, list['PostTasksBodyTaskCustomPropertiesItem']]): - """ - - kind: str - content: str - due_at: datetime.datetime - priority: Union[Unset, int] = UNSET - performer_ids: Union[Unset, list[int]] = UNSET - custom_properties: Union[Unset, list["PostTasksBodyTaskCustomPropertiesItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - kind = self.kind - - content = self.content - - due_at = self.due_at.isoformat() - - priority = self.priority - - performer_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.performer_ids, Unset): - performer_ids = self.performer_ids - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "kind": kind, - "content": content, - "due_at": due_at, - } - ) - if priority is not UNSET: - field_dict["priority"] = priority - if performer_ids is not UNSET: - field_dict["performer_ids"] = performer_ids - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.post_tasks_body_task_custom_properties_item import PostTasksBodyTaskCustomPropertiesItem - - d = src_dict.copy() - kind = d.pop("kind") - - content = d.pop("content") - - due_at = isoparse(d.pop("due_at")) - - priority = d.pop("priority", UNSET) - - performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = PostTasksBodyTaskCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - post_tasks_body_task = cls( - kind=kind, - content=content, - due_at=due_at, - priority=priority, - performer_ids=performer_ids, - custom_properties=custom_properties, - ) - - post_tasks_body_task.additional_properties = d - return post_tasks_body_task - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py deleted file mode 100644 index 279e511..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_body_task_custom_properties_item.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostTasksBodyTaskCustomPropertiesItem") - - -@_attrs_define -class PostTasksBodyTaskCustomPropertiesItem: - """ - Attributes: - id (Union[Unset, int]): Идентификатор поля - value (Union[Unset, str]): Значение поля - """ - - id: Union[Unset, int] = UNSET - value: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - value = self.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if value is not UNSET: - field_dict["value"] = value - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - value = d.pop("value", UNSET) - - post_tasks_body_task_custom_properties_item = cls( - id=id, - value=value, - ) - - post_tasks_body_task_custom_properties_item.additional_properties = d - return post_tasks_body_task_custom_properties_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py deleted file mode 100644 index 5dcd6b7..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.post_tasks_response_201_data import PostTasksResponse201Data - - -T = TypeVar("T", bound="PostTasksResponse201") - - -@_attrs_define -class PostTasksResponse201: - """ - Attributes: - data (Union[Unset, PostTasksResponse201Data]): - """ - - data: Union[Unset, "PostTasksResponse201Data"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.post_tasks_response_201_data import PostTasksResponse201Data - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, PostTasksResponse201Data] - if isinstance(_data, Unset): - data = UNSET - else: - data = PostTasksResponse201Data.from_dict(_data) - - post_tasks_response_201 = cls( - data=data, - ) - - post_tasks_response_201.additional_properties = d - return post_tasks_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py deleted file mode 100644 index b714c69..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data.py +++ /dev/null @@ -1,177 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.post_tasks_response_201_data_custom_properties_item import ( - PostTasksResponse201DataCustomPropertiesItem, - ) - - -T = TypeVar("T", bound="PostTasksResponse201Data") - - -@_attrs_define -class PostTasksResponse201Data: - """ - Attributes: - id (Union[Unset, int]): Идентификатор созданного напоминания - kind (Union[Unset, str]): Тип - content (Union[Unset, str]): Описание - due_at (Union[Unset, datetime.datetime]): Срок выполнения (ISO-8601) - priority (Union[Unset, int]): Приоритет - user_id (Union[Unset, int]): Идентификатор пользователя-создателя - status (Union[Unset, str]): Статус напоминания - created_at (Union[Unset, datetime.datetime]): Дата и время создания - performer_ids (Union[Unset, list[int]]): - custom_properties (Union[Unset, list['PostTasksResponse201DataCustomPropertiesItem']]): - """ - - id: Union[Unset, int] = UNSET - kind: Union[Unset, str] = UNSET - content: Union[Unset, str] = UNSET - due_at: Union[Unset, datetime.datetime] = UNSET - priority: Union[Unset, int] = UNSET - user_id: Union[Unset, int] = UNSET - status: Union[Unset, str] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - performer_ids: Union[Unset, list[int]] = UNSET - custom_properties: Union[Unset, list["PostTasksResponse201DataCustomPropertiesItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - kind = self.kind - - content = self.content - - due_at: Union[Unset, str] = UNSET - if not isinstance(self.due_at, Unset): - due_at = self.due_at.isoformat() - - priority = self.priority - - user_id = self.user_id - - status = self.status - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - performer_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.performer_ids, Unset): - performer_ids = self.performer_ids - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if kind is not UNSET: - field_dict["kind"] = kind - if content is not UNSET: - field_dict["content"] = content - if due_at is not UNSET: - field_dict["due_at"] = due_at - if priority is not UNSET: - field_dict["priority"] = priority - if user_id is not UNSET: - field_dict["user_id"] = user_id - if status is not UNSET: - field_dict["status"] = status - if created_at is not UNSET: - field_dict["created_at"] = created_at - if performer_ids is not UNSET: - field_dict["performer_ids"] = performer_ids - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.post_tasks_response_201_data_custom_properties_item import ( - PostTasksResponse201DataCustomPropertiesItem, - ) - - d = src_dict.copy() - id = d.pop("id", UNSET) - - kind = d.pop("kind", UNSET) - - content = d.pop("content", UNSET) - - _due_at = d.pop("due_at", UNSET) - due_at: Union[Unset, datetime.datetime] - if isinstance(_due_at, Unset): - due_at = UNSET - else: - due_at = isoparse(_due_at) - - priority = d.pop("priority", UNSET) - - user_id = d.pop("user_id", UNSET) - - status = d.pop("status", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = PostTasksResponse201DataCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - post_tasks_response_201_data = cls( - id=id, - kind=kind, - content=content, - due_at=due_at, - priority=priority, - user_id=user_id, - status=status, - created_at=created_at, - performer_ids=performer_ids, - custom_properties=custom_properties, - ) - - post_tasks_response_201_data.additional_properties = d - return post_tasks_response_201_data - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py deleted file mode 100644 index 1dc217e..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_201_data_custom_properties_item.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostTasksResponse201DataCustomPropertiesItem") - - -@_attrs_define -class PostTasksResponse201DataCustomPropertiesItem: - """ - Attributes: - id (Union[Unset, int]): Идентификатор поля - name (Union[Unset, str]): Название поля - data_type (Union[Unset, str]): Тип поля (string, number, date или link) - value (Union[Unset, str]): Значение - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - data_type: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - data_type = self.data_type - - value = self.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if data_type is not UNSET: - field_dict["data_type"] = data_type - if value is not UNSET: - field_dict["value"] = value - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - data_type = d.pop("data_type", UNSET) - - value = d.pop("value", UNSET) - - post_tasks_response_201_data_custom_properties_item = cls( - id=id, - name=name, - data_type=data_type, - value=value, - ) - - post_tasks_response_201_data_custom_properties_item.additional_properties = d - return post_tasks_response_201_data_custom_properties_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py deleted file mode 100644 index e5ca651..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/post_tasks_response_400.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostTasksResponse400") - - -@_attrs_define -class PostTasksResponse400: - """ - Attributes: - error (Union[Unset, str]): Описание ошибки - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_tasks_response_400 = cls( - error=error, - ) - - post_tasks_response_400.additional_properties = d - return post_tasks_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py deleted file mode 100644 index 24a5140..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_body.py +++ /dev/null @@ -1,72 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.edit_messages import EditMessages - - -T = TypeVar("T", bound="PutMessagesIdBody") - - -@_attrs_define -class PutMessagesIdBody: - """ - Attributes: - message (Union[Unset, EditMessages]): Для получения сообщения вам необходимо знать его id и указать его в URL - запроса. - """ - - message: Union[Unset, "EditMessages"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - message: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.message, Unset): - message = self.message.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if message is not UNSET: - field_dict["message"] = message - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.edit_messages import EditMessages - - d = src_dict.copy() - _message = d.pop("message", UNSET) - message: Union[Unset, EditMessages] - if isinstance(_message, Unset): - message = UNSET - else: - message = EditMessages.from_dict(_message) - - put_messages_id_body = cls( - message=message, - ) - - put_messages_id_body.additional_properties = d - return put_messages_id_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py deleted file mode 100644 index 5cb478f..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_messages_id_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="PutMessagesIdResponse200") - - -@_attrs_define -class PutMessagesIdResponse200: - """ - Attributes: - data (Union[Unset, list['Message']]): Созданное сообщение - """ - - data: Union[Unset, list["Message"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Message.from_dict(data_item_data) - - data.append(data_item) - - put_messages_id_response_200 = cls( - data=data, - ) - - put_messages_id_response_200.additional_properties = d - return put_messages_id_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py deleted file mode 100644 index a34d4e0..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/put_status_response_201.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.status_type_0 import StatusType0 - - -T = TypeVar("T", bound="PutStatusResponse201") - - -@_attrs_define -class PutStatusResponse201: - """ - Attributes: - data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. - """ - - data: Union["StatusType0", None, Unset] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.status_type_0 import StatusType0 - - data: Union[None, Unset, dict[str, Any]] - if isinstance(self.data, Unset): - data = UNSET - elif isinstance(self.data, StatusType0): - data = self.data.to_dict() - else: - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.status_type_0 import StatusType0 - - d = src_dict.copy() - - def _parse_data(data: object) -> Union["StatusType0", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - componentsschemas_status_type_0 = StatusType0.from_dict(data) - - return componentsschemas_status_type_0 - except: # noqa: E722 - pass - return cast(Union["StatusType0", None, Unset], data) - - data = _parse_data(d.pop("data", UNSET)) - - put_status_response_201 = cls( - data=data, - ) - - put_status_response_201.additional_properties = d - return put_status_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py deleted file mode 100644 index f3e1788..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_chat.py +++ /dev/null @@ -1,91 +0,0 @@ -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryChat") - - -@_attrs_define -class QueryChat: - """Собранный объект параметров создаваемой беседы или канала - - Attributes: - name (str): Название Example: 🤿 aqua. - member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, которые станут участниками Example: - [186, 187]. - channel (Union[Unset, bool]): Тип: беседа (по умолчанию, false) или канал (true) Example: True. - public (Union[Unset, bool]): Доступ: закрытый (по умолчанию, false) или открытый (true) - """ - - name: str - member_ids: Union[Unset, list[int]] = UNSET - channel: Union[Unset, bool] = UNSET - public: Union[Unset, bool] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - name = self.name - - member_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.member_ids, Unset): - member_ids = self.member_ids - - channel = self.channel - - public = self.public - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "name": name, - } - ) - if member_ids is not UNSET: - field_dict["member_ids"] = member_ids - if channel is not UNSET: - field_dict["channel"] = channel - if public is not UNSET: - field_dict["public"] = public - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - name = d.pop("name") - - member_ids = cast(list[int], d.pop("member_ids", UNSET)) - - channel = d.pop("channel", UNSET) - - public = d.pop("public", UNSET) - - query_chat = cls( - name=name, - member_ids=member_ids, - channel=channel, - public=public, - ) - - query_chat.additional_properties = d - return query_chat - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py deleted file mode 100644 index f575b43..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_common_methods.py +++ /dev/null @@ -1,77 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryCommonMethods") - - -@_attrs_define -class QueryCommonMethods: - """получение списка актульных полей сущности. - - Attributes: - id (Union[Unset, int]): Название поля Example: 1. - name (Union[Unset, str]): Идентификатор поля Example: Дата рождения. - data_type (Union[Unset, str]): тип поля (string, number, date или link) Example: number. - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - data_type: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - data_type = self.data_type - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if data_type is not UNSET: - field_dict["data_type"] = data_type - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - data_type = d.pop("data_type", UNSET) - - query_common_methods = cls( - id=id, - name=name, - data_type=data_type, - ) - - query_common_methods.additional_properties = d - return query_common_methods - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py deleted file mode 100644 index 885c9fc..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.query_status_status import QueryStatusStatus - - -T = TypeVar("T", bound="QueryStatus") - - -@_attrs_define -class QueryStatus: - """ - Attributes: - status (Union[Unset, QueryStatusStatus]): Собранный объект параметров нового статуса - """ - - status: Union[Unset, "QueryStatusStatus"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - status: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.status, Unset): - status = self.status.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if status is not UNSET: - field_dict["status"] = status - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.query_status_status import QueryStatusStatus - - d = src_dict.copy() - _status = d.pop("status", UNSET) - status: Union[Unset, QueryStatusStatus] - if isinstance(_status, Unset): - status = UNSET - else: - status = QueryStatusStatus.from_dict(_status) - - query_status = cls( - status=status, - ) - - query_status.additional_properties = d - return query_status - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py deleted file mode 100644 index 48858ea..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/query_status_status.py +++ /dev/null @@ -1,102 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryStatusStatus") - - -@_attrs_define -class QueryStatusStatus: - """Собранный объект параметров нового статуса - - Attributes: - emoji (str): Emoji символ статуса - title (str): Текст статуса - expires_at (Union[None, Unset, datetime.datetime]): Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM- - DDThh:mm:ss.sssZ - """ - - emoji: str - title: str - expires_at: Union[None, Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - emoji = self.emoji - - title = self.title - - expires_at: Union[None, Unset, str] - if isinstance(self.expires_at, Unset): - expires_at = UNSET - elif isinstance(self.expires_at, datetime.datetime): - expires_at = self.expires_at.isoformat() - else: - expires_at = self.expires_at - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "emoji": emoji, - "title": title, - } - ) - if expires_at is not UNSET: - field_dict["expires_at"] = expires_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - emoji = d.pop("emoji") - - title = d.pop("title") - - def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - expires_at_type_0 = isoparse(data) - - return expires_at_type_0 - except: # noqa: E722 - pass - return cast(Union[None, Unset, datetime.datetime], data) - - expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) - - query_status_status = cls( - emoji=emoji, - title=title, - expires_at=expires_at, - ) - - query_status_status.additional_properties = d - return query_status_status - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py deleted file mode 100644 index de28f69..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/reaction.py +++ /dev/null @@ -1,86 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Reaction") - - -@_attrs_define -class Reaction: - """ - Attributes: - user_id (Union[Unset, int]): Идентификатор пользователя, оставившего реакцию. - created_at (Union[Unset, datetime.datetime]): Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY- - MM-DDThh:mm:ss.sssZ. - code (Union[Unset, str]): Emoji символ реакции. - """ - - user_id: Union[Unset, int] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - code: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - user_id = self.user_id - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - code = self.code - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if user_id is not UNSET: - field_dict["user_id"] = user_id - if created_at is not UNSET: - field_dict["created_at"] = created_at - if code is not UNSET: - field_dict["code"] = code - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - user_id = d.pop("user_id", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - code = d.pop("code", UNSET) - - reaction = cls( - user_id=user_id, - created_at=created_at, - code=code, - ) - - reaction.additional_properties = d - return reaction - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py deleted file mode 100644 index 8997cfe..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/status_type_0.py +++ /dev/null @@ -1,101 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="StatusType0") - - -@_attrs_define -class StatusType0: - """Статус. Возвращается как null, если статус не установлен. - - Attributes: - emoji (Union[Unset, str]): Emoji символ статуса - title (Union[Unset, str]): Текст статуса - expires_at (Union[None, Unset, datetime.datetime]): Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM- - DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - """ - - emoji: Union[Unset, str] = UNSET - title: Union[Unset, str] = UNSET - expires_at: Union[None, Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - emoji = self.emoji - - title = self.title - - expires_at: Union[None, Unset, str] - if isinstance(self.expires_at, Unset): - expires_at = UNSET - elif isinstance(self.expires_at, datetime.datetime): - expires_at = self.expires_at.isoformat() - else: - expires_at = self.expires_at - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if emoji is not UNSET: - field_dict["emoji"] = emoji - if title is not UNSET: - field_dict["title"] = title - if expires_at is not UNSET: - field_dict["expires_at"] = expires_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - emoji = d.pop("emoji", UNSET) - - title = d.pop("title", UNSET) - - def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - expires_at_type_0 = isoparse(data) - - return expires_at_type_0 - except: # noqa: E722 - pass - return cast(Union[None, Unset, datetime.datetime], data) - - expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) - - status_type_0 = cls( - emoji=emoji, - title=title, - expires_at=expires_at, - ) - - status_type_0.additional_properties = d - return status_type_0 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py deleted file mode 100644 index 6504540..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/tag.py +++ /dev/null @@ -1,77 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Tag") - - -@_attrs_define -class Tag: - """Для получения тега вам необходимо знать его id и указать его в URL запроса. - - Attributes: - id (Union[Unset, int]): Идентификатор тега - name (Union[Unset, str]): Название тега - users_count (Union[Unset, int]): Количество сотрудников, которые имеют этот тег - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - users_count: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - users_count = self.users_count - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if users_count is not UNSET: - field_dict["users_count"] = users_count - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - users_count = d.pop("users_count", UNSET) - - tag = cls( - id=id, - name=name, - users_count=users_count, - ) - - tag.additional_properties = d - return tag - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed deleted file mode 100644 index 1aad327..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/py.typed +++ /dev/null @@ -1 +0,0 @@ -# Marker file for PEP 561 \ No newline at end of file diff --git a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py b/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py deleted file mode 100644 index b9ed58b..0000000 --- a/pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/types.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Contains some shared types for properties""" - -from collections.abc import MutableMapping -from http import HTTPStatus -from typing import BinaryIO, Generic, Literal, Optional, TypeVar - -from attrs import define - - -class Unset: - def __bool__(self) -> Literal[False]: - return False - - -UNSET: Unset = Unset() - -FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] - - -@define -class File: - """Contains information for file uploads""" - - payload: BinaryIO - file_name: Optional[str] = None - mime_type: Optional[str] = None - - def to_tuple(self) -> FileJsonType: - """Return a tuple representation that httpx will accept for multipart/form-data""" - return self.file_name, self.payload, self.mime_type - - -T = TypeVar("T") - - -@define -class Response(Generic[T]): - """A response from an endpoint""" - - status_code: HTTPStatus - content: bytes - headers: MutableMapping[str, str] - parsed: Optional[T] - - -__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/pachca-api-open-api-3-0-client/pyproject.toml b/pachca-api-open-api-3-0-client/pyproject.toml deleted file mode 100644 index da5dcfa..0000000 --- a/pachca-api-open-api-3-0-client/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[tool.poetry] -name = "pachca-api-open-api-3-0-client" -version = "3.0.3" -description = "A client library for accessing PachcaAPI - OpenAPI 3.0" -authors = [] -readme = "README.md" -packages = [ - {include = "pachca_api_open_api_3_0_client"}, -] -include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] - - -[tool.poetry.dependencies] -python = "^3.9" -httpx = ">=0.20.0,<0.29.0" -attrs = ">=22.2.0" -python-dateutil = "^2.8.0" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.ruff] -line-length = 120 - -[tool.ruff.lint] -select = ["F", "I", "UP"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 530696c..0000000 --- a/requirements.txt +++ /dev/null @@ -1,27 +0,0 @@ -annotated-types==0.7.0 -anyio==4.7.0 -attrs==24.3.0 -certifi==2024.12.14 -click==8.1.8 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.27.2 -idna==3.10 -Jinja2==3.1.5 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mdurl==0.1.2 -openapi-python-client==0.23.0 -pydantic==2.10.4 -pydantic_core==2.27.2 -Pygments==2.18.0 -python-dateutil==2.9.0.post0 -rich==13.9.4 -ruamel.yaml==0.18.6 -ruamel.yaml.clib==0.2.12 -ruff==0.8.4 -shellingham==1.5.4 -six==1.17.0 -sniffio==1.3.1 -typer==0.15.1 -typing_extensions==4.12.2 diff --git a/src/generator1/README.md b/src/generator1/README.md new file mode 100644 index 0000000..b942afc --- /dev/null +++ b/src/generator1/README.md @@ -0,0 +1,22 @@ +Генерация Клиента через openapi-python-client + +Инструкция (работать в папке generator1): +1. В venv прописать + +pip install openapi-python-client + +2. Сгенерировать клиент командой + +openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite + +3. Запустить скрипт-генератор + +python script.py + +4. Установить pachca-api-open-api-3-0-client в venv командой + +pip install ./pachca-api-open-api-3-0-client + +5. Запустить скрипт-пример запроса + +python pachca.py \ No newline at end of file diff --git a/openapi.yaml b/src/generator1/openapi.yaml similarity index 100% rename from openapi.yaml rename to src/generator1/openapi.yaml diff --git a/pachca.py b/src/generator1/pachca.py similarity index 68% rename from pachca.py rename to src/generator1/pachca.py index 431f6b0..bf5bef7 100644 --- a/pachca.py +++ b/src/generator1/pachca.py @@ -15,13 +15,15 @@ ) -async def main(): - task2 = asyncio.create_task(pachca.createChat(body=chat_body)) - task3 = asyncio.create_task(pachca.getEmployees()) +async def main() -> None: + """ Функция теста эндпоинтов """ - print(await task2) + task1 = asyncio.create_task(pachca.createChat(body=chat_body)) + task2 = asyncio.create_task(pachca.getEmployees()) + + print(await task1) print('*' * 30) - print(await task3) + print(await task2) if __name__ == '__main__': diff --git a/script.py b/src/generator1/script.py similarity index 100% rename from script.py rename to src/generator1/script.py diff --git a/templates/client.py.jinja b/src/generator1/templates/client.py.jinja similarity index 100% rename from templates/client.py.jinja rename to src/generator1/templates/client.py.jinja diff --git a/templates/endpoint_macros.py.jinja b/src/generator1/templates/endpoint_macros.py.jinja similarity index 100% rename from templates/endpoint_macros.py.jinja rename to src/generator1/templates/endpoint_macros.py.jinja diff --git a/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja similarity index 100% rename from templates/endpoint_module.py.jinja rename to src/generator1/templates/endpoint_module.py.jinja diff --git a/templates/macros/client_macros.py.jinja b/src/generator1/templates/macros/client_macros.py.jinja similarity index 100% rename from templates/macros/client_macros.py.jinja rename to src/generator1/templates/macros/client_macros.py.jinja diff --git a/src/generator2/README.md b/src/generator2/README.md new file mode 100644 index 0000000..48c6c32 --- /dev/null +++ b/src/generator2/README.md @@ -0,0 +1,4 @@ +Генерация Клиента через прямой код Python + +Инструкция: +... \ No newline at end of file diff --git a/src/repository/README.md b/src/repository/README.md new file mode 100644 index 0000000..5e32573 --- /dev/null +++ b/src/repository/README.md @@ -0,0 +1 @@ +Результат - Библиотека \ No newline at end of file diff --git a/src/requirements.txt b/src/requirements.txt index 9815348..530696c 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1 +1,27 @@ -# Основные зависимости здесь +annotated-types==0.7.0 +anyio==4.7.0 +attrs==24.3.0 +certifi==2024.12.14 +click==8.1.8 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.27.2 +idna==3.10 +Jinja2==3.1.5 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdurl==0.1.2 +openapi-python-client==0.23.0 +pydantic==2.10.4 +pydantic_core==2.27.2 +Pygments==2.18.0 +python-dateutil==2.9.0.post0 +rich==13.9.4 +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.12 +ruff==0.8.4 +shellingham==1.5.4 +six==1.17.0 +sniffio==1.3.1 +typer==0.15.1 +typing_extensions==4.12.2 From 170e24d8fdf0e7e517756380a69eae833aad4650 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 27 Dec 2024 23:52:57 +0300 Subject: [PATCH 086/296] relocate requirements in generator1 --- src/{ => generator1}/requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => generator1}/requirements.txt (100%) diff --git a/src/requirements.txt b/src/generator1/requirements.txt similarity index 100% rename from src/requirements.txt rename to src/generator1/requirements.txt From dd39bd697f0b966883ca42b3045482debd1b8121 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 28 Dec 2024 00:14:08 +0300 Subject: [PATCH 087/296] add builder dir --- src/builder/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/builder/README.md diff --git a/src/builder/README.md b/src/builder/README.md new file mode 100644 index 0000000..a0a9484 --- /dev/null +++ b/src/builder/README.md @@ -0,0 +1 @@ +Инструменты для генерации библиотеки \ No newline at end of file From 9168664540523ebd882bf10523ef1beaa150b5b9 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 28 Dec 2024 11:08:35 +0300 Subject: [PATCH 088/296] pydantic models generation for request bosy, path query params --- constants.py | 10 ++++++ generate_pydantic_model.py | 72 ++++++++++++++++++++++++++++++++++++++ openapi.yaml | 21 ++++++----- schema_link_processor.py | 33 +++++++++++++++++ yaml_loader.py | 7 ++++ yaml_processor.py | 67 +++++++++++++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 9 deletions(-) create mode 100644 constants.py create mode 100644 generate_pydantic_model.py create mode 100644 schema_link_processor.py create mode 100644 yaml_loader.py create mode 100644 yaml_processor.py diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..6514d36 --- /dev/null +++ b/constants.py @@ -0,0 +1,10 @@ +PATH_TO_YAML = './openapi.yaml' + +PYTHON_TYPES = { + 'string': 'str', + 'integer': 'int', + 'boolean': 'bool', +} +HTTP_METHODS = ( + 'get', 'post', 'put', 'update', 'patch', 'delete' +) diff --git a/generate_pydantic_model.py b/generate_pydantic_model.py new file mode 100644 index 0000000..8ae64c5 --- /dev/null +++ b/generate_pydantic_model.py @@ -0,0 +1,72 @@ +from constants import PYTHON_TYPES +from schema_link_processor import ( + simple_replace_ref_with_schema, replace_ref_with_schema +) + + +def create_model(name: str, fields: list): + model_code = f'class {name}(BaseModel):\n' + for field in fields: + if field[2]: + model_code += ( + f' {field[0]}: {field[1]}\n' + ) + else: + model_code += ( + f' {field[0]}: Optional[{field[1]}]\n' + ) + return model_code + + +def look_into_schema(schema: dict): + """Рекурсивно разбирает схему и генерирует модели pydantic для requestBody. + """ + list_of_properties = [] + nested_properties = [] + required_properties = [] + upper_schema_name = list(schema.keys())[0] + inner_schema = schema.get(upper_schema_name).get('properties') + required_properties = schema.get(upper_schema_name).get('required', []) + for property in inner_schema: + inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) + property_type = ( + PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) + if property_type == 'object': + property_type = property.capitalize() + if property_type == 'array': + list_type = inner_body.get("items").get("type") + if list_type == 'object' or list_type == 'array': + list_type = property.capitalize() + property_type = (f'List[{list_type}]') + list_of_properties.append( + ( + property, + property_type, + True if property in required_properties else False + ) + ) + if (inner_body.get('type') == 'object' + or inner_body.get('type') == 'array' + and inner_body.get('items', {}).get('properties') + or inner_body.get('items', {}).get('items')): + nested_properties.append(property) + for nested in nested_properties: + if ('items' in inner_schema.get(nested) + and inner_schema.get(nested).get('items').get('properties')): + look_into_schema(replace_ref_with_schema( + {nested.capitalize(): inner_schema.get(nested).get('items')}) + ) + elif ('items' in inner_schema.get(nested) + and inner_schema.get(nested).get('items').get('items')): + look_into_schema(replace_ref_with_schema( + { + nested.capitalize(): + inner_schema.get(nested).get('items').get('items') + }) + ) + else: + look_into_schema(replace_ref_with_schema( + {nested.capitalize(): inner_schema.get(nested)}) + ) + + print(create_model(upper_schema_name, list_of_properties)) diff --git a/openapi.yaml b/openapi.yaml index 7a6d84a..3942c83 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -130,7 +130,7 @@ paths: maximum: 50 - name: page in: query - description: Страница выборки (по умолчанию 1) + description: Страница выборки (по умолчанию 1) required: false schema: type: integer @@ -138,7 +138,7 @@ paths: - name: query in: query description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) required: false schema: type: string @@ -420,7 +420,7 @@ paths: maximum: 50 - name: page in: query - description: Страница выборки (по умолчанию 1) + description: Страница выборки (по умолчанию 1) required: false schema: type: integer @@ -438,7 +438,7 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Поле имеет недопустимое значение content: application/json: schema: @@ -829,6 +829,7 @@ paths: delete: tags: - talk and channel participants + operationId: leaveChat summary: 'Выход из беседы или канала' description: |- Метод для самостоятельного выхода из беседы или канала. @@ -1198,7 +1199,8 @@ paths: code: not_found put: tags: - - messages + - message + operationId: editMessage summary: Редактирование сообщения description: Метод для редактирования сообщения или комментария. parameters: @@ -1504,6 +1506,7 @@ paths: post: tags: - reminders + operationId: createTask summary: 'Метод для создания нового напоминания.' description: | При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. @@ -1758,11 +1761,11 @@ components: Status: type: object nullable: true - description: Статус. Возвращается как null, если статус не установлен. + description: Статус. Возвращается как null, если статус не установлен. properties: emoji: type: string - description: Emoji символ статуса + description: Emoji символ статуса title: type: string description: Текст статуса @@ -1795,7 +1798,7 @@ components: nullable: true QueryCommonMethods: type: object - description: получение списка актульных полей сущности. + description: получение списка актульных полей сущности. properties: id: type: integer @@ -2219,4 +2222,4 @@ components: type: http scheme: bearer security: - - bearerAuth: [] + - bearerAuth: [] \ No newline at end of file diff --git a/schema_link_processor.py b/schema_link_processor.py new file mode 100644 index 0000000..1726fd8 --- /dev/null +++ b/schema_link_processor.py @@ -0,0 +1,33 @@ +from yaml_loader import YAML_DICT + + +def load_schema(path_to_schema: str): + schema_name = path_to_schema.split('/')[-1] + return YAML_DICT.get('components').get('schemas').get(schema_name) + + +def replace_ref_with_schema(schema: dict): + schema_name = list(schema.keys())[0] + if 'properties' in schema.get(schema_name): + current_schema = schema.get(schema_name).get('properties') + if 'items' in schema.get(schema_name): + current_schema = schema.get(schema_name).get('items') + for property in current_schema: + if '$ref' in current_schema.get(property): + current_schema[property] = load_schema( + current_schema.get(property).get('$ref')) + return schema + + +def simple_replace_ref_with_schema(schema): + key = '' + if 'properties' in schema: + key = 'properties' + elif 'items' in schema: + key = 'items' + else: + return schema + if '$ref' not in schema[key]: + return schema + schema[key] = load_schema(schema[key].get('$ref')) + return schema diff --git a/yaml_loader.py b/yaml_loader.py new file mode 100644 index 0000000..482eba1 --- /dev/null +++ b/yaml_loader.py @@ -0,0 +1,7 @@ +from pathlib import Path +from ruamel.yaml import YAML + +from constants import PATH_TO_YAML + + +YAML_DICT = YAML(typ='rt').load(Path(PATH_TO_YAML)) diff --git a/yaml_processor.py b/yaml_processor.py new file mode 100644 index 0000000..29982d3 --- /dev/null +++ b/yaml_processor.py @@ -0,0 +1,67 @@ +from constants import HTTP_METHODS +from generate_pydantic_model import look_into_schema +from schema_link_processor import replace_ref_with_schema, load_schema +from yaml_loader import YAML_DICT + + +def get_all_endpoints(YAML_DICT: dict): + endpoints = YAML_DICT.get('paths') + method = {} + for path, body in endpoints.items(): + for method_name in HTTP_METHODS: + method_body = body.get(method_name) + if method_body: + method[method_name] = method_body + for body in method.values(): + yield path, body + method.clear() + + +def process_endpoints(): + body: dict + for endpoint, body in get_all_endpoints(YAML_DICT): + print(endpoint) + operationId = body.get('operationId') + + print(operationId) + parameters = body.get('parameters') + path_parameters = [] + query_parameters = [] + if parameters: + for parameter in parameters: + required = parameter.get('required', False) + if required: + path_parameters.append( + ( + parameter.get('name'), + parameter.get('schema').get('type') + ) + ) + else: + query_parameters.append( + ( + parameter.get('name'), + parameter.get('schema').get('type') + ) + ) + print('path: ', path_parameters) + print('query: ', query_parameters) + requestBody = body.get('requestBody') + if requestBody: + schema = ( + requestBody.get('content').get('application/json') + or requestBody.get('content').get('multipart/form-data')) + if not schema: + break + schema_has_link = schema.get('schema').get('$ref', False) + schema = ( + {operationId.capitalize(): load_schema(schema_has_link)} + if schema_has_link + else {operationId.capitalize(): schema.get('schema')} + ) + look_into_schema(replace_ref_with_schema(schema)) + print('='*80) + + +if __name__ == '__main__': + process_endpoints() From 96878f3a6e7675c84435eed0524377b1810ec8f4 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 28 Dec 2024 12:56:01 +0300 Subject: [PATCH 089/296] some ruff errors fix --- src/generator2/constants.py | 2 +- src/generator2/generate_pydantic_model.py | 23 +++++++++------- src/generator2/schema_link_processor.py | 9 ++++--- src/generator2/yaml_processor.py | 33 ++++++++++++----------- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/generator2/constants.py b/src/generator2/constants.py index 6514d36..536dec5 100644 --- a/src/generator2/constants.py +++ b/src/generator2/constants.py @@ -6,5 +6,5 @@ 'boolean': 'bool', } HTTP_METHODS = ( - 'get', 'post', 'put', 'update', 'patch', 'delete' + 'get', 'post', 'put', 'update', 'patch', 'delete', ) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 070ecdd..f56c573 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -1,10 +1,11 @@ from constants import PYTHON_TYPES from schema_link_processor import ( - simple_replace_ref_with_schema, replace_ref_with_schema + replace_ref_with_schema, simple_replace_ref_with_schema, ) -def create_model(name: str, fields: list): +def create_model(name: str, fields: list) -> str: + """Генерирует код модели Pydantic.""" model_code = f'class {name}(BaseModel):\n' for field in fields: if field[2]: @@ -18,8 +19,10 @@ def create_model(name: str, fields: list): return model_code -def look_into_schema(schema: dict): - """Рекурсивно разбирает схему и генерирует модели pydantic для requestBody. +def look_into_schema(schema: dict) -> None: + """Рекурсивно разбирает схемы. + + Генерирует модели pydantic для requestBody. """ list_of_properties = [] nested_properties = [] @@ -42,8 +45,8 @@ def look_into_schema(schema: dict): ( property, property_type, - True if property in required_properties else False - ) + True if property in required_properties else False, + ), ) if (inner_body.get('type') == 'object' or inner_body.get('type') == 'array' @@ -54,18 +57,18 @@ def look_into_schema(schema: dict): if ('items' in inner_schema.get(nested) and inner_schema.get(nested).get('items').get('properties')): look_into_schema(replace_ref_with_schema( - {nested.capitalize(): inner_schema.get(nested).get('items')}) + {nested.capitalize(): inner_schema.get(nested).get('items')}), ) elif ('items' in inner_schema.get(nested) and inner_schema.get(nested).get('items').get('items')): look_into_schema(replace_ref_with_schema( { nested.capitalize(): - inner_schema.get(nested).get('items').get('items') - }) + inner_schema.get(nested).get('items').get('items'), + }), ) else: look_into_schema(replace_ref_with_schema( - {nested.capitalize(): inner_schema.get(nested)}) + {nested.capitalize(): inner_schema.get(nested)}), ) print(create_model(upper_schema_name, list_of_properties)) diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 1726fd8..2ace485 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -1,12 +1,14 @@ from yaml_loader import YAML_DICT -def load_schema(path_to_schema: str): +def load_schema(path_to_schema: str) -> dict: + """Возвращает схему из ссылки.""" schema_name = path_to_schema.split('/')[-1] return YAML_DICT.get('components').get('schemas').get(schema_name) -def replace_ref_with_schema(schema: dict): +def replace_ref_with_schema(schema: dict) -> dict: + """Заменяет ссылку на схему самой схемой.""" schema_name = list(schema.keys())[0] if 'properties' in schema.get(schema_name): current_schema = schema.get(schema_name).get('properties') @@ -19,7 +21,8 @@ def replace_ref_with_schema(schema: dict): return schema -def simple_replace_ref_with_schema(schema): +def simple_replace_ref_with_schema(schema: dict) -> dict: + """Заменяет ссылку на схему самой схемой.""" key = '' if 'properties' in schema: key = 'properties' diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index c6796f4..a3520c8 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -1,11 +1,13 @@ +from typing import Generator from constants import HTTP_METHODS from generate_pydantic_model import look_into_schema from schema_link_processor import replace_ref_with_schema, load_schema from yaml_loader import YAML_DICT -def get_all_endpoints(YAML_DICT: dict): - endpoints = YAML_DICT.get('paths') +def get_all_endpoints(yaml_dict: dict) -> Generator[tuple]: + """Получает все эндпоинты из path документации.""" + endpoints = yaml_dict.get('paths') method = {} for path, body in endpoints.items(): for method_name in HTTP_METHODS: @@ -17,13 +19,14 @@ def get_all_endpoints(YAML_DICT: dict): method.clear() -def process_endpoints(): +def process_endpoints() -> tuple[list, list]: + """Обрабатывает эндпоинты.""" body: dict for endpoint, body in get_all_endpoints(YAML_DICT): print(endpoint) - operationId = body.get('operationId') + operation_id = body.get('operationId') - print(operationId) + print(operation_id) parameters = body.get('parameters') path_parameters = [] query_parameters = [] @@ -34,30 +37,30 @@ def process_endpoints(): path_parameters.append( ( parameter.get('name'), - parameter.get('schema').get('type') - ) + parameter.get('schema').get('type'), + ), ) else: query_parameters.append( ( parameter.get('name'), - parameter.get('schema').get('type') - ) + parameter.get('schema').get('type'), + ), ) print('path: ', path_parameters) print('query: ', query_parameters) - requestBody = body.get('requestBody') - if requestBody: + request_body = body.get('requestBody') + if request_body: schema = ( - requestBody.get('content').get('application/json') - or requestBody.get('content').get('multipart/form-data')) + request_body.get('content').get('application/json') + or request_body.get('content').get('multipart/form-data')) if not schema: break schema_has_link = schema.get('schema').get('$ref', False) schema = ( - {operationId.capitalize(): load_schema(schema_has_link)} + {operation_id.capitalize(): load_schema(schema_has_link)} if schema_has_link - else {operationId.capitalize(): schema.get('schema')} + else {operation_id.capitalize(): schema.get('schema')} ) look_into_schema(replace_ref_with_schema(schema)) From bfe9b0d2ccf0d2901a67326eedaa30b50cd00c8b Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 28 Dec 2024 15:52:08 +0300 Subject: [PATCH 090/296] add YAML-file in src dir --- src/openapi.yaml | 2226 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2226 insertions(+) create mode 100644 src/openapi.yaml diff --git a/src/openapi.yaml b/src/openapi.yaml new file mode 100644 index 0000000..dec1f58 --- /dev/null +++ b/src/openapi.yaml @@ -0,0 +1,2226 @@ +openapi: 3.0.3 +info: + title: PachcaAPI - OpenAPI 3.0 + description: Документация к открытому API пачки + version: 3.0.3 +servers: + - url: https://api.pachca.com/api/shared/v1 + +tags: + - name: common methods + description: Everything about common methods + - name: employees + description: Everything about employees + - name: status + description: Everything about + status + - name: tags + description: Everything about + tags + - name: chats and channels + description: Everything about + chats and channels + - name: talk and channel participants + description: Everything about + talk and channel participants + - name: comments + description: Everything about + comments + - name: messages + description: Everything about + messages + - name: reactions to messages + description: Everything about + reactions to messages + - name: reminders + description: Everything about + reminders + +paths: + /custom_properties: + get: + tags: + - common methods + summary: Список дополнительных полей + description: | + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + operationId: getCommonMethods + parameters: + - name: entity_type + in: query + description: Тип сущности - участник (User) или напоминание (Task). + required: true + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/QueryCommonMethods' + '400': + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + BLANK: + summary: blank + description: Поле не может быть пустым + value: + detail: BLANK + INCLUSION: + summary: inclusion + description: Поле имеет непредусмотренное значение + value: + detail: INCLUSION + /uploads: + post: + tags: + - common methods + summary: Получение подписи и ключа для загрузки файла + description: Возвращает параметры, необходимые для безопасной загрузки файла. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + /direct_url: + post: + tags: + - common methods + summary: Получение URL для загрузки + description: Отправляет запрос для получения URL для безопасной загрузки файла. + operationId: getDirectUrl + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + responses: + '204': + description: Успешный запрос. + /users: + get: + tags: + - employees + summary: получение актуального списка всех сотрудников компании + description: | + Fetch a paginated list of employees with optional filtering by query. + operationId: getEmployees + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), + email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Employee' + /users/{id}: + get: + tags: + - employees + summary: получение информации о сотруднике + description: | + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + operationId: getEmployee + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Employee' + '404': + description: Сотрудник не найден + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + /profile/status: + get: + tags: + - status + summary: получение информации о своем статусе + description: | + Параметры запроса отсутствуют + operationId: getStatus + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + put: + tags: + - status + summary: новый статус + description: | + Создание нового статуса. + operationId: putStatus + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' + responses: + '201': + description: Объект создан + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + '400': + description: BadRequest + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + BLANK: + summary: blank + description: Обязательное поле (не может быть пустым) + value: + detail: BLANK + TOO_LONG: + summary: too_long + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + detail: TOO_LONG + INVALID: + summary: invalid + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + detail: INVALID + WRONG_EMOJI: + summary: wrong_emoji + description: Emoji статуса не может содержать значения отличные от Emoji символа + value: + detail: WRONG_EMOJI + delete: + tags: + - status + summary: удаление своего статуса + description: | + Параметры запроса отсутствуют + operationId: delStatus + responses: + '204': + description: Объект успешно удален, тело ответа отсутствует + content: {} + /group_tags/{id}: + get: + tags: + - tags + summary: Информация о теге + description: | + Параметры запроса отсутствуют + operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + "404": + description: Тег не найден. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Тег не найден. + value: + errors: + - key: "id" + value: "100500" + message: "Не удалось найти тег" + code: "not_found" + /group_tags: + get: + tags: + - tags + summary: Список тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + exclusion: + summary: Недопустимое значение количество возвращаемых сущностей за один запрос + value: + errors: + - key: "per" + value: "51" + message: "Поле имеет недопустимое значение" + code: "exclusion" + /group_tags/{id}/users: + get: + tags: + - tags + operationId: getTagsEmployees + summary: получение актуального списка сотрудников тега + description: | + Метод для получения актуального списка сотрудников тега. + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BaseEmployee' + '400': + description: Поле имеет недопустимое значение + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + /chats: + post: + tags: + - chats and channels + operationId: createChat + summary: Новая беседа или канал + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + chat: + $ref: '#/components/schemas/QueryChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + get: + tags: + - chats and channels + operationId: getChats + summary: Список бесед и каналов + description: Получения списка бесед и каналов по заданным параметрам. + parameters: + - name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + - name: per + in: query + required: false + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + required: false + description: Страница выборки (по умолчанию 1) + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/ErrorsCode' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}: + get: + tags: + - chats and channels + operationId: getChat + summary: Информация о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /chats/{id}/members: + post: + tags: + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов пользователей, которые станут участниками + content: + application/json: + schema: + required: + - member_ids + type: object + properties: + member_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + responses: + '201': + description: Пользователи добавлены + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /chats/{id}/group_tags: + post: + tags: + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + responses: + '201': + description: Тег(и) добавлен(ы) + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: 'Выход из беседы или канала' + description: |- + Метод для самостоятельного выхода из беседы или канала. + parameters: + - name: id + in: path + required: true + description: 'Уникальный идентификатор беседы или канала.' + schema: + type: integer + responses: + '200': + description: 'Успешно отписан. Тело ответа отсутствует' + '400': + description: 'Нельзя покинуть персональный чат' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /messages/{id}/thread: + post: + tags: + - comments + summary: Создание нового треда + description: | + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '200': + description: Тред успешно создан или возвращены данные существующего треда. + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного треда. + chat_id: + type: integer + description: Идентификатор чата треда. + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + '404': + description: Сообщение не найдено. + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + '400': + description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + /messages: + post: + tags: + - messages + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' + example: + message: + entity_type: discussion + entity_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + responses: + '201': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + example: + errors: + - key: entyti_id + value: 1 + message: Не удалось найти + code: not_found + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - key: content + value: null + message: Поле не может быть пустым + code: blank + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - key: entity_type + value: chat + message: Поле имеет недопустимое значение + code: exclusion + get: + tags: + - messages + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + operationId: getListMessage + parameters: + - name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: | + Количество возвращаемых сущностей за один запрос + (по умолчанию 25, максимум 50) + schema: + title: per + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + schema: + title: page + type: integer + default: 1 + responses: + '200': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + errors: + - key: chat_id + value: 1 + message: Не удалось найти + code: not_found + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - key: chat_id + value: null + message: Поле не может быть пустым + code: blank + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - key: chat_id + value: chat + message: Поле имеет недопустимое значение + code: exclusion + /messages/{id}: + get: + tags: + - messages + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + description: Successfull + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + errors: + - key: id + value: 0 + message: Не удалось найти + code: not_found + put: + tags: + - message + operationId: editMessage + summary: Редактирование сообщения + description: Метод для редактирования сообщения или комментария. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/EditMessages' + responses: + '200': + description: Успешно отредактировано + content: + application/json: + schema: + type: object + properties: + data: + type: array + description: Созданное сообщение + items: + $ref: '#/components/schemas/Message' + '400': + description: Нельзя покинуть персональный чат + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /messages/{id}/reactions: + post: + tags: + - reactions to messages + operationId: postMessageReactions + summary: Добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + description: Emoji в строковом формате для добавления реакции. + required: + - code + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + blank_field: + summary: Поле code пустое + value: + error: blank + exclusion: + summary: Недопустимое значение эмодзи + value: + error: exclusion + + "403": + description: Превышение лимитов по реакциям. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + user_limit: + summary: Превышен лимит уникальных реакций пользователя + value: + error: user_limit + message: "Вы можете добавить не более 20 уникальных реакций." + unique_limit: + summary: Превышен лимит уникальных реакций на сообщение + value: + error: unique_limit + message: "Сообщение может содержать не более 30 уникальных реакций." + general_limit: + summary: Превышен общий лимит реакций на сообщение + value: + error: general_limit + message: "Сообщение может содержать не более 1000 реакций." + + "404": + description: Сообщение не найдено. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Сообщение не найдено. + examples: + not_found: + summary: Сообщение не существует + value: + error: not_found + delete: + tags: + - reactions to messages + operationId: deleteMessageReactions + summary: Удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + - name: code + in: query + required: true + description: Emoji, который нужно удалить. + schema: + type: string + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + blank_field: + summary: Поле code пустое + value: + errors: + - key: "code" + value: "" + message: "Поле не может быть пустым" + code: "blank" + exclusion: + summary: Недопустимое значение эмодзи + value: + errors: + - key: "code" + value: "invalid_emoji" + message: "Поле имеет недопустимое значение" + code: "exclusion" + + "404": + description: Сообщение или реакция не найдены. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Сообщение или реакция не найдены + value: + errors: + - key: "reaction" + value: "😊" + message: "Не удалось найти реакцию" + code: "not_found" + get: + tags: + - reactions to messages + summary: 'Получение актуального списка реакций.' + description: | + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. + operationId: getMessageReactions + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. + schema: + type: integer + requestBody: + required: false + content: + application/json: + schema: + type: object + properties: + per: + type: integer + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). + default: 50 + maximum: 50 + page: + type: integer + description: Номер страницы выборки (по умолчанию 1). + default: 1 + responses: + '200': + description: Список реакций успешно получен. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Reaction' + '404': + description: Сообщение не найдено. + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + '400': + description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + /tasks: + post: + tags: + - reminders + operationId: createTask + summary: 'Метод для создания нового напоминания.' + description: | + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + kind: + type: string + description: Тип + content: + type: string + description: Описание + due_at: + type: string + format: date-time + description: Срок выполнения (ISO-8601) + priority: + type: integer + description: Приоритет + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + performer_ids: + type: array + items: + type: integer + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + + '400': + description: Ошибка запроса + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки + +components: + schemas: + BaseEmployee: + type: object + properties: + id: + type: integer + example: 1 + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + role: + type: string + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + bot: + type: boolean + description: | + Тип: пользователь (false) или бот (true) + description: Базовый класс сотрудника. + FileResponse: + type: object + properties: + Content-Disposition: + type: string + acl: + type: string + policy: + type: string + x-amz-credential: + type: string + x-amz-algorithm: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + key: + type: string + direct_url: + type: string + DirectResponse: + type: object + properties: + Content-Disposition: + type: string + acl: + type: string + policy: + type: string + x-amz-credential: + type: string + x-amz-algorithm: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + key: + type: string + file: + type: string + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + type: object + properties: + status: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + nullable: true + QueryCommonMethods: + type: object + description: получение списка актульных полей сущности. + properties: + id: + type: integer + example: 1 + description: Название поля + name: + type: string + example: Дата рождения + description: Идентификатор поля + data_type: + type: string + example: number + description: тип поля (string, number, date или link) + NotFound: + description: Объект не найден + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Страница не найдена." + type: string + Errors: + title: Errors + type: array + items: + title: Error + type: object + properties: + key: + title: key + type: string + value: + title: value + type: string + message: + title: message + type: string + code: + title: code + type: string + payload: + title: payload + type: object + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + CreateMessage: + type: object + required: + - entity_id + - content + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + files: + title: Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + name: + title: Name + type: string + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + size: + title: Size + type: integer + buttons: + title: buttons + $ref: '#/components/schemas/Buttons' + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false + EditMessages: + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + properties: + content: + type: string + description: Текст сообщения + default: Текст сообщения + files: + type: object + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - 'file' + - 'image' + size: + type: integer + default: 1234 + description: Размер файла в байтах, отображаемый пользователю + buttons: + type: array + description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. + items: + type: array + items: + type: object + properties: + text: + type: string + description: Текст, отображаемый на кнопке пользователю + url: + type: string + description: Ссылка, которая будет открыта по нажатию кнопки + data: + type: string + description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + Message: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + format: date-time + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + description: Размер файла в байтах, отображаемый пользователю + buttons: + title: buttons + $ref: '#/components/schemas/Buttons' + thread: + title: Thread + type: object + nullable: true + default: null + properties: + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + forwarding: + title: Forwarding + type: object + nullable: true + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + Reaction: + type: object + properties: + user_id: + type: integer + description: | + Идентификатор пользователя, оставившего реакцию. + created_at: + type: string + format: date-time + description: | + Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + code: + type: string + description: | + Emoji символ реакции. + BadRequest: + type: object + properties: + error: + type: string + message: + type: string + ErrorsCode: + description: Bad Request + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + Chat: + type: object + description: Беседа или канал + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + name: + type: string + description: Название + example: 🤿 aqua + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + member_ids: + type: array + description: Массив идентификаторов пользователей, участников + items: + type: integer + example: + - 185 + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (false) или открытый (true)' + example: false + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + QueryChat: + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer + securitySchemes: + bearerAuth: + type: http + scheme: bearer +security: + - bearerAuth: [] From 006e52eaa27360bb5a49b8933c2248a5c7adebbf Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 28 Dec 2024 18:13:25 +0300 Subject: [PATCH 091/296] fixed list types, added fields ot models --- src/generator2/generate_pydantic_model.py | 12 ++++++++++-- src/generator2/yaml_processor.py | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index f56c573..0e6587b 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -10,11 +10,13 @@ def create_model(name: str, fields: list) -> str: for field in fields: if field[2]: model_code += ( - f' {field[0]}: {field[1]}\n' + f' {field[0]}: {field[1]} ' + '= Field(..., \'docstring\')\n' ) else: model_code += ( - f' {field[0]}: Optional[{field[1]}]\n' + f' {field[0]}: Optional[{field[1]}] ' + '= Field(None, \'docstring\')\n' ) return model_code @@ -32,12 +34,18 @@ def look_into_schema(schema: dict) -> None: required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) + # inner_type = inner_body.get('type') + # if inner_type in PYTHON_TYPES: + # property_type = PYTHON_TYPES[inner_type] + # else: + # property_type = inner_type property_type = ( PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) if property_type == 'object': property_type = property.capitalize() if property_type == 'array': list_type = inner_body.get("items").get("type") + list_type = PYTHON_TYPES.get(list_type, list_type) if list_type == 'object' or list_type == 'array': list_type = property.capitalize() property_type = (f'List[{list_type}]') diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index a3520c8..6001405 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -5,7 +5,7 @@ from yaml_loader import YAML_DICT -def get_all_endpoints(yaml_dict: dict) -> Generator[tuple]: +def get_all_endpoints(yaml_dict: dict): """Получает все эндпоинты из path документации.""" endpoints = yaml_dict.get('paths') method = {} From 200a09728ef3be3415bee766e4467c16375eb182 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 28 Dec 2024 18:16:09 +0300 Subject: [PATCH 092/296] remove commented code --- src/generator2/generate_pydantic_model.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 0e6587b..ef05867 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -34,11 +34,6 @@ def look_into_schema(schema: dict) -> None: required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) - # inner_type = inner_body.get('type') - # if inner_type in PYTHON_TYPES: - # property_type = PYTHON_TYPES[inner_type] - # else: - # property_type = inner_type property_type = ( PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) if property_type == 'object': From 932b089ae665eccae82c2654ae2bc5be286257bd Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 11:47:21 +0300 Subject: [PATCH 093/296] add description for field --- src/generator2/generate_pydantic_model.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index ef05867..ff7e27a 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -11,12 +11,12 @@ def create_model(name: str, fields: list) -> str: if field[2]: model_code += ( f' {field[0]}: {field[1]} ' - '= Field(..., \'docstring\')\n' + f'= Field(..., \'{field[3]}\')\n' ) else: model_code += ( f' {field[0]}: Optional[{field[1]}] ' - '= Field(None, \'docstring\')\n' + f'= Field(None, \'{field[3]}\')\n' ) return model_code @@ -34,6 +34,7 @@ def look_into_schema(schema: dict) -> None: required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) + description = inner_body.get('description', 'No docstring provided') property_type = ( PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) if property_type == 'object': @@ -49,6 +50,7 @@ def look_into_schema(schema: dict) -> None: property, property_type, True if property in required_properties else False, + description, ), ) if (inner_body.get('type') == 'object' From e115584dc3b94be906f9ec2458ee194592d0e5ee Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 11:56:57 +0300 Subject: [PATCH 094/296] README.md edit, add some instructions --- src/generator2/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/generator2/README.md b/src/generator2/README.md index 48c6c32..8e3c377 100644 --- a/src/generator2/README.md +++ b/src/generator2/README.md @@ -1,4 +1,10 @@ Генерация Клиента через прямой код Python Инструкция: -... \ No newline at end of file +... + +# Генерация моделей pydantic для requestBosy эндпоинтов + +Метод process_endpoints в yaml_processor.py позволяет создать модели pydantic для каждого эндпоинта +Метод возвращает кортеж из двух список - path query параметров эндпоинта +Метод записывает (пока что в консоль) модели pydantic. \ No newline at end of file From 0428bc25eb64bf7ce084ad9535d14fc38378aca5 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 11:57:55 +0300 Subject: [PATCH 095/296] README.ms typo fix --- src/generator2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generator2/README.md b/src/generator2/README.md index 8e3c377..7c7290d 100644 --- a/src/generator2/README.md +++ b/src/generator2/README.md @@ -3,7 +3,7 @@ Инструкция: ... -# Генерация моделей pydantic для requestBosy эндпоинтов +# Генерация моделей pydantic для requestBody эндпоинтов Метод process_endpoints в yaml_processor.py позволяет создать модели pydantic для каждого эндпоинта Метод возвращает кортеж из двух список - path query параметров эндпоинта From 4d99d37a98dfae018a85bb43c5a69042d6601a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 12:58:11 +0300 Subject: [PATCH 096/296] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20=D0=B2=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=86=D0=B5=D1=81=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 30 +++ src/generator2/README.md | 10 - src/generator2/api_methods.py | 244 ++++++++++++++++++++++ src/generator2/constants.py | 10 - src/generator2/gen_class_pachca.py | 140 +++++++++++++ src/generator2/generate_pydantic_model.py | 79 ------- src/generator2/pachca.py | 24 +++ src/generator2/schema_link_processor.py | 36 ---- src/generator2/yaml_loader.py | 7 - src/generator2/yaml_processor.py | 72 ------- 10 files changed, 438 insertions(+), 214 deletions(-) create mode 100644 requirements.txt delete mode 100644 src/generator2/README.md create mode 100644 src/generator2/api_methods.py delete mode 100644 src/generator2/constants.py create mode 100644 src/generator2/gen_class_pachca.py delete mode 100644 src/generator2/generate_pydantic_model.py create mode 100644 src/generator2/pachca.py delete mode 100644 src/generator2/schema_link_processor.py delete mode 100644 src/generator2/yaml_loader.py delete mode 100644 src/generator2/yaml_processor.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a004395 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,30 @@ +anyio==4.7.0 +attrs==24.3.0 +certifi==2024.12.14 +chardet==5.2.0 +charset-normalizer==3.4.1 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +idna==3.10 +jsonschema==4.23.0 +jsonschema-spec==0.2.4 +jsonschema-specifications==2023.7.1 +lazy-object-proxy==1.10.0 +openapi-schema-validator==0.6.2 +openapi-spec-validator==0.6.0 +openapi3-parser==1.1.19 +packaging==24.2 +pathable==0.4.3 +prance==23.6.21.0 +PyYAML==6.0.2 +referencing==0.30.2 +requests==2.32.3 +rfc3339-validator==0.1.4 +rpds-py==0.22.3 +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.12 +six==1.17.0 +sniffio==1.3.1 +typing_extensions==4.12.2 +urllib3==2.3.0 diff --git a/src/generator2/README.md b/src/generator2/README.md deleted file mode 100644 index 7c7290d..0000000 --- a/src/generator2/README.md +++ /dev/null @@ -1,10 +0,0 @@ -Генерация Клиента через прямой код Python - -Инструкция: -... - -# Генерация моделей pydantic для requestBody эндпоинтов - -Метод process_endpoints в yaml_processor.py позволяет создать модели pydantic для каждого эндпоинта -Метод возвращает кортеж из двух список - path query параметров эндпоинта -Метод записывает (пока что в консоль) модели pydantic. \ No newline at end of file diff --git a/src/generator2/api_methods.py b/src/generator2/api_methods.py new file mode 100644 index 0000000..fad9fbd --- /dev/null +++ b/src/generator2/api_methods.py @@ -0,0 +1,244 @@ +"""Сгенерированные методы запроса.""" + + +async def get_common_methods(self, param_query=None): + """Список дополнительных полей + +Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. +""" + client = await self.get_client() + async with client: + response = await client.get('/custom_properties', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_uploads(self, param_query=None): + """Получение подписи и ключа для загрузки файла + +Возвращает параметры, необходимые для безопасной загрузки файла.""" + client = await self.get_client() + async with client: + response = await client.post('/uploads', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_direct_url(self, param_query=None): + """Получение URL для загрузки + +Отправляет запрос для получения URL для безопасной загрузки файла.""" + client = await self.get_client() + async with client: + response = await client.post('/direct_url', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_employees(self, param_query=None): + """получение актуального списка всех сотрудников компании + +Fetch a paginated list of employees with optional filtering by query. +""" + client = await self.get_client() + async with client: + response = await client.get('/users', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_employee(self, id, param_query=None): + """получение информации о сотруднике + +Метод для получения информации о сотруднике. +Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. +""" + client = await self.get_client() + async with client: + response = await client.get(f'/users/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def del_status(self, param_query=None): + """удаление своего статуса + +Параметры запроса отсутствуют +""" + client = await self.get_client() + async with client: + response = await client.delete('/profile/status', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_tag(self, id, param_query=None): + """Информация о теге + +Параметры запроса отсутствуют +""" + client = await self.get_client() + async with client: + response = await client.get(f'/group_tags/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_tags(self, param_query=None): + """Список тегов сотрудников + +Метод для получения актуального списка тегов сотрудников. +""" + client = await self.get_client() + async with client: + response = await client.get('/group_tags', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_tags_employees(self, id, param_query=None): + """получение актуального списка сотрудников тега + +Метод для получения актуального списка сотрудников тега. +""" + client = await self.get_client() + async with client: + response = await client.get(f'/group_tags/{id}/users', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_chat(self, param_query=None): + """Новая беседа или канал + +Метод для создания новой беседы или нового канала. +При создании беседы или канала вы автоматически становитесь участником.\ +""" + client = await self.get_client() + async with client: + response = await client.post('/chats', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_chat(self, id, param_query=None): + """Информация о беседе или канале + +Получения информации о беседе или канале. +Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. +""" + client = await self.get_client() + async with client: + response = await client.get(f'/chats/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def post_members_to_chats(self, id, param_query=None): + """добавление пользователей в состав участников + +Метод для добавления пользователей в состав участников беседы или канала. +""" + client = await self.get_client() + async with client: + response = await client.post(f'/chats/{id}/members', params=param_query) + response.raise_for_status() + return response.json() + + +async def post_tags_to_chats(self, id, param_query=None): + """добавление тегов в состав участников беседы или канала + +Метод для добавления тегов в состав участников беседы или канала. +""" + client = await self.get_client() + async with client: + response = await client.post(f'/chats/{id}/group_tags', params=param_query) + response.raise_for_status() + return response.json() + + +async def leave_chat(self, id, param_query=None): + """Выход из беседы или канала + +Метод для самостоятельного выхода из беседы или канала.""" + client = await self.get_client() + async with client: + response = await client.delete(f'/chats/{id}/leave', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_thread(self, id, param_query=None): + """Создание нового треда + +Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. +""" + client = await self.get_client() + async with client: + response = await client.post(f'/messages/{id}/thread', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_message(self, param_query=None): + """создание нового сообщения + +Метод для отправки сообщения в беседу или канал, +личного сообщения пользователю или комментария в тред. + +При использовании entity_type: "discussion" (или просто без указания entity_type) +допускается отправка любого chat_id в поле entity_id. +То есть, сообщение можно отправить зная только идентификатор чата. +При этом, вы имеете возможность отправить сообщение в тред по его идентификатору +или личное сообщение по идентификатору пользователя. + +Для отправки личного сообщения пользователю создавать чат не требуется. +Достаточно указать entity_type: "user" и идентификатор пользователя. +Чат будет создан автоматически, если между вами ещё не было переписки. +Между двумя пользователями может быть только один личный чат. +""" + client = await self.get_client() + async with client: + response = await client.post('/messages', params=param_query) + response.raise_for_status() + return response.json() + + +async def edit_message(self, id, param_query=None): + """Редактирование сообщения + +Метод для редактирования сообщения или комментария.""" + client = await self.get_client() + async with client: + response = await client.put(f'/messages/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def delete_message_reactions(self, id, param_query=None): + """Удаление реакции + +Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. +""" + client = await self.get_client() + async with client: + response = await client.delete(f'/messages/{id}/reactions', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_task(self, param_query=None): + """Метод для создания нового напоминания. + +При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. +При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. +Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. +У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. +""" + client = await self.get_client() + async with client: + response = await client.post('/tasks', params=param_query) + response.raise_for_status() + return response.json() + diff --git a/src/generator2/constants.py b/src/generator2/constants.py deleted file mode 100644 index 536dec5..0000000 --- a/src/generator2/constants.py +++ /dev/null @@ -1,10 +0,0 @@ -PATH_TO_YAML = './openapi.yaml' - -PYTHON_TYPES = { - 'string': 'str', - 'integer': 'int', - 'boolean': 'bool', -} -HTTP_METHODS = ( - 'get', 'post', 'put', 'update', 'patch', 'delete', -) diff --git a/src/generator2/gen_class_pachca.py b/src/generator2/gen_class_pachca.py new file mode 100644 index 0000000..67c3439 --- /dev/null +++ b/src/generator2/gen_class_pachca.py @@ -0,0 +1,140 @@ +import inspect +import re +from typing import Union + +import httpx +from openapi_parser import parse +from openapi_parser.specification import Path, Schema, Server, Specification + +import api_methods + +TOKEN = 'Bearer l62qW6VgnJMMWx53QmwRbKEy84dzo2LhJl0Mst9m2W8' + + +async def get_client(self): + """Клиент генерируемого класса""" + return httpx.AsyncClient( + base_url=self.base_url, + headers={'Authorization': TOKEN} + ) + + +def get_obj_openapi_spec( + path_to_file='./src/generator2/openapi.yaml' +) -> Specification: + """Читает спецификацию openapi из файла openapi.yaml и возвращает + спецификацию в виде объекта Specification библиотеки openapi_parser""" + with open(path_to_file, 'r', encoding='utf-8') as file: + spec_openapi = file.read() + + return parse(spec_string=spec_openapi) + + +def collecting_class_properites(module) -> dict[str, Union[object, str]]: + """Собирает генерируемые функции из модуля api_methods.py + добавляет свойства класса и статичные функции.""" + dict_func = {} + + for name, obj in inspect.getmembers(module): + if inspect.isfunction(obj): + dict_func[name] = obj + + dict_func['get_client'] = get_client + + return dict_func + + +def gen_template(paths: Path) -> list[str]: + """Собирает параметры запроса всех paths спецификации + Возвращает список шаблонов функций""" + functions = [] + + for path in paths: + url = path.url + for operation in path.operations: + method_request = operation.method.value.lower() + function_name = '_'.join( + re.findall(r'[a-z]+|[A-Z][^A-Z]*', operation.operation_id) + ).lower() + docstring = (f'"""{operation.summary}\n' + f'\n{operation.description}"""') # Создать функцию для редактирования docstring + param_path = None + param_query = {} + # print(operation.parameters) + for param in operation.parameters: + if param.location.value == 'path': + param_path = param.name + if param.location.value == 'query': + param_query[param.name] = param.schema.default if param.schema.default else None + + # print(url) + functions.append( + get_template_methods( + function_name, + url, + method_request, + param_path, + param_query, + docstring + ) + ) + + return functions + + +def get_template_methods( + name_func, + url, + method_request, + param_path, + param_query, + docstring +): + """Возвращает шаблон генерируемой функции. + Вызывается в функции gen_template""" + if param_path: + function_declaration = (f"async def {name_func}" + f"(self, {param_path}, param_query=None):") + response = (f"response = await client.{method_request}" + f"(f'{url}', params=param_query)") + else: + function_declaration = f"async def {name_func}(self, param_query=None):" + response = (f"response = await client.{method_request}" + f"('{url}', params=param_query)") + return f""" +{function_declaration} + {docstring} + client = await self.get_client() + async with client: + {response} + response.raise_for_status() + return response.json() + +""" + + +spec: Specification = get_obj_openapi_spec() +servers: list[Server] = spec.servers +paths: list[Path] = spec.paths +schemas: dict[str, Schema] = spec.schemas +base_url = base_url = servers[0].url + +dict_properties_class = collecting_class_properites(api_methods) + +dict_properties_class['get_client'] = get_client # Добавляем метод get_client + +dict_properties_class['base_url'] = base_url # Добавляем свойство класса base_url + +PachcaBot: object = type('PachcaBot', (object,), dict_properties_class) + + +if __name__ == "__main__": + + templates = gen_template(paths) + + with open( + './src/generator2/api_methods.py', 'w', encoding='utf-8' + ) as file: + file.write('"""Сгенерированные методы запроса."""\n\n') + for template in templates: + file.write(template) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py deleted file mode 100644 index ff7e27a..0000000 --- a/src/generator2/generate_pydantic_model.py +++ /dev/null @@ -1,79 +0,0 @@ -from constants import PYTHON_TYPES -from schema_link_processor import ( - replace_ref_with_schema, simple_replace_ref_with_schema, -) - - -def create_model(name: str, fields: list) -> str: - """Генерирует код модели Pydantic.""" - model_code = f'class {name}(BaseModel):\n' - for field in fields: - if field[2]: - model_code += ( - f' {field[0]}: {field[1]} ' - f'= Field(..., \'{field[3]}\')\n' - ) - else: - model_code += ( - f' {field[0]}: Optional[{field[1]}] ' - f'= Field(None, \'{field[3]}\')\n' - ) - return model_code - - -def look_into_schema(schema: dict) -> None: - """Рекурсивно разбирает схемы. - - Генерирует модели pydantic для requestBody. - """ - list_of_properties = [] - nested_properties = [] - required_properties = [] - upper_schema_name = list(schema.keys())[0] - inner_schema = schema.get(upper_schema_name).get('properties') - required_properties = schema.get(upper_schema_name).get('required', []) - for property in inner_schema: - inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) - description = inner_body.get('description', 'No docstring provided') - property_type = ( - PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) - if property_type == 'object': - property_type = property.capitalize() - if property_type == 'array': - list_type = inner_body.get("items").get("type") - list_type = PYTHON_TYPES.get(list_type, list_type) - if list_type == 'object' or list_type == 'array': - list_type = property.capitalize() - property_type = (f'List[{list_type}]') - list_of_properties.append( - ( - property, - property_type, - True if property in required_properties else False, - description, - ), - ) - if (inner_body.get('type') == 'object' - or inner_body.get('type') == 'array' - and inner_body.get('items', {}).get('properties') - or inner_body.get('items', {}).get('items')): - nested_properties.append(property) - for nested in nested_properties: - if ('items' in inner_schema.get(nested) - and inner_schema.get(nested).get('items').get('properties')): - look_into_schema(replace_ref_with_schema( - {nested.capitalize(): inner_schema.get(nested).get('items')}), - ) - elif ('items' in inner_schema.get(nested) - and inner_schema.get(nested).get('items').get('items')): - look_into_schema(replace_ref_with_schema( - { - nested.capitalize(): - inner_schema.get(nested).get('items').get('items'), - }), - ) - else: - look_into_schema(replace_ref_with_schema( - {nested.capitalize(): inner_schema.get(nested)}), - ) - print(create_model(upper_schema_name, list_of_properties)) diff --git a/src/generator2/pachca.py b/src/generator2/pachca.py new file mode 100644 index 0000000..4c80c49 --- /dev/null +++ b/src/generator2/pachca.py @@ -0,0 +1,24 @@ +import asyncio +from gen_class_pachca import PachcaBot + +if __name__ == '__main__': + + print(id(PachcaBot)) + + pachca = PachcaBot() + + print(hasattr(pachca, 'client')) + + #print(hasattr(pachca, 'get_custom_properties')) + + async def run_pachca(): + print(await pachca.get_employee(id=514505)) + print(await pachca.get_employees(param_query={'per': 1})) + print(await pachca.get_tags()) + print(await pachca.get_tags_employees(id=27470)) + print(await pachca.get_common_methods()) #Возвращает ошибку, нужно прописать обработку если (parameters.query и parameters.required) + + asyncio.run(run_pachca()) + + print(type(pachca)) + print(pachca.__class__.__name__) \ No newline at end of file diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py deleted file mode 100644 index 2ace485..0000000 --- a/src/generator2/schema_link_processor.py +++ /dev/null @@ -1,36 +0,0 @@ -from yaml_loader import YAML_DICT - - -def load_schema(path_to_schema: str) -> dict: - """Возвращает схему из ссылки.""" - schema_name = path_to_schema.split('/')[-1] - return YAML_DICT.get('components').get('schemas').get(schema_name) - - -def replace_ref_with_schema(schema: dict) -> dict: - """Заменяет ссылку на схему самой схемой.""" - schema_name = list(schema.keys())[0] - if 'properties' in schema.get(schema_name): - current_schema = schema.get(schema_name).get('properties') - if 'items' in schema.get(schema_name): - current_schema = schema.get(schema_name).get('items') - for property in current_schema: - if '$ref' in current_schema.get(property): - current_schema[property] = load_schema( - current_schema.get(property).get('$ref')) - return schema - - -def simple_replace_ref_with_schema(schema: dict) -> dict: - """Заменяет ссылку на схему самой схемой.""" - key = '' - if 'properties' in schema: - key = 'properties' - elif 'items' in schema: - key = 'items' - else: - return schema - if '$ref' not in schema[key]: - return schema - schema[key] = load_schema(schema[key].get('$ref')) - return schema diff --git a/src/generator2/yaml_loader.py b/src/generator2/yaml_loader.py deleted file mode 100644 index 482eba1..0000000 --- a/src/generator2/yaml_loader.py +++ /dev/null @@ -1,7 +0,0 @@ -from pathlib import Path -from ruamel.yaml import YAML - -from constants import PATH_TO_YAML - - -YAML_DICT = YAML(typ='rt').load(Path(PATH_TO_YAML)) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py deleted file mode 100644 index 6001405..0000000 --- a/src/generator2/yaml_processor.py +++ /dev/null @@ -1,72 +0,0 @@ -from typing import Generator -from constants import HTTP_METHODS -from generate_pydantic_model import look_into_schema -from schema_link_processor import replace_ref_with_schema, load_schema -from yaml_loader import YAML_DICT - - -def get_all_endpoints(yaml_dict: dict): - """Получает все эндпоинты из path документации.""" - endpoints = yaml_dict.get('paths') - method = {} - for path, body in endpoints.items(): - for method_name in HTTP_METHODS: - method_body = body.get(method_name) - if method_body: - method[method_name] = method_body - for body in method.values(): - yield path, body - method.clear() - - -def process_endpoints() -> tuple[list, list]: - """Обрабатывает эндпоинты.""" - body: dict - for endpoint, body in get_all_endpoints(YAML_DICT): - print(endpoint) - operation_id = body.get('operationId') - - print(operation_id) - parameters = body.get('parameters') - path_parameters = [] - query_parameters = [] - if parameters: - for parameter in parameters: - required = parameter.get('required', False) - if required: - path_parameters.append( - ( - parameter.get('name'), - parameter.get('schema').get('type'), - ), - ) - else: - query_parameters.append( - ( - parameter.get('name'), - parameter.get('schema').get('type'), - ), - ) - print('path: ', path_parameters) - print('query: ', query_parameters) - request_body = body.get('requestBody') - if request_body: - schema = ( - request_body.get('content').get('application/json') - or request_body.get('content').get('multipart/form-data')) - if not schema: - break - schema_has_link = schema.get('schema').get('$ref', False) - schema = ( - {operation_id.capitalize(): load_schema(schema_has_link)} - if schema_has_link - else {operation_id.capitalize(): schema.get('schema')} - ) - look_into_schema(replace_ref_with_schema(schema)) - - print('='*80) - return path_parameters, query_parameters - - -if __name__ == '__main__': - process_endpoints() From 7e3783a9e0c740d2ce3c2b86706638378290410c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 12:59:40 +0300 Subject: [PATCH 097/296] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20=D0=B2=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=86=D0=B5=D1=81=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generator2/api_methods.py | 244 ---------------------------------- 1 file changed, 244 deletions(-) diff --git a/src/generator2/api_methods.py b/src/generator2/api_methods.py index fad9fbd..e69de29 100644 --- a/src/generator2/api_methods.py +++ b/src/generator2/api_methods.py @@ -1,244 +0,0 @@ -"""Сгенерированные методы запроса.""" - - -async def get_common_methods(self, param_query=None): - """Список дополнительных полей - -Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. -""" - client = await self.get_client() - async with client: - response = await client.get('/custom_properties', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_uploads(self, param_query=None): - """Получение подписи и ключа для загрузки файла - -Возвращает параметры, необходимые для безопасной загрузки файла.""" - client = await self.get_client() - async with client: - response = await client.post('/uploads', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_direct_url(self, param_query=None): - """Получение URL для загрузки - -Отправляет запрос для получения URL для безопасной загрузки файла.""" - client = await self.get_client() - async with client: - response = await client.post('/direct_url', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_employees(self, param_query=None): - """получение актуального списка всех сотрудников компании - -Fetch a paginated list of employees with optional filtering by query. -""" - client = await self.get_client() - async with client: - response = await client.get('/users', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_employee(self, id, param_query=None): - """получение информации о сотруднике - -Метод для получения информации о сотруднике. -Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. -""" - client = await self.get_client() - async with client: - response = await client.get(f'/users/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def del_status(self, param_query=None): - """удаление своего статуса - -Параметры запроса отсутствуют -""" - client = await self.get_client() - async with client: - response = await client.delete('/profile/status', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_tag(self, id, param_query=None): - """Информация о теге - -Параметры запроса отсутствуют -""" - client = await self.get_client() - async with client: - response = await client.get(f'/group_tags/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_tags(self, param_query=None): - """Список тегов сотрудников - -Метод для получения актуального списка тегов сотрудников. -""" - client = await self.get_client() - async with client: - response = await client.get('/group_tags', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_tags_employees(self, id, param_query=None): - """получение актуального списка сотрудников тега - -Метод для получения актуального списка сотрудников тега. -""" - client = await self.get_client() - async with client: - response = await client.get(f'/group_tags/{id}/users', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_chat(self, param_query=None): - """Новая беседа или канал - -Метод для создания новой беседы или нового канала. -При создании беседы или канала вы автоматически становитесь участником.\ -""" - client = await self.get_client() - async with client: - response = await client.post('/chats', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_chat(self, id, param_query=None): - """Информация о беседе или канале - -Получения информации о беседе или канале. -Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. -""" - client = await self.get_client() - async with client: - response = await client.get(f'/chats/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def post_members_to_chats(self, id, param_query=None): - """добавление пользователей в состав участников - -Метод для добавления пользователей в состав участников беседы или канала. -""" - client = await self.get_client() - async with client: - response = await client.post(f'/chats/{id}/members', params=param_query) - response.raise_for_status() - return response.json() - - -async def post_tags_to_chats(self, id, param_query=None): - """добавление тегов в состав участников беседы или канала - -Метод для добавления тегов в состав участников беседы или канала. -""" - client = await self.get_client() - async with client: - response = await client.post(f'/chats/{id}/group_tags', params=param_query) - response.raise_for_status() - return response.json() - - -async def leave_chat(self, id, param_query=None): - """Выход из беседы или канала - -Метод для самостоятельного выхода из беседы или канала.""" - client = await self.get_client() - async with client: - response = await client.delete(f'/chats/{id}/leave', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_thread(self, id, param_query=None): - """Создание нового треда - -Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. -""" - client = await self.get_client() - async with client: - response = await client.post(f'/messages/{id}/thread', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_message(self, param_query=None): - """создание нового сообщения - -Метод для отправки сообщения в беседу или канал, -личного сообщения пользователю или комментария в тред. - -При использовании entity_type: "discussion" (или просто без указания entity_type) -допускается отправка любого chat_id в поле entity_id. -То есть, сообщение можно отправить зная только идентификатор чата. -При этом, вы имеете возможность отправить сообщение в тред по его идентификатору -или личное сообщение по идентификатору пользователя. - -Для отправки личного сообщения пользователю создавать чат не требуется. -Достаточно указать entity_type: "user" и идентификатор пользователя. -Чат будет создан автоматически, если между вами ещё не было переписки. -Между двумя пользователями может быть только один личный чат. -""" - client = await self.get_client() - async with client: - response = await client.post('/messages', params=param_query) - response.raise_for_status() - return response.json() - - -async def edit_message(self, id, param_query=None): - """Редактирование сообщения - -Метод для редактирования сообщения или комментария.""" - client = await self.get_client() - async with client: - response = await client.put(f'/messages/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def delete_message_reactions(self, id, param_query=None): - """Удаление реакции - -Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. -""" - client = await self.get_client() - async with client: - response = await client.delete(f'/messages/{id}/reactions', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_task(self, param_query=None): - """Метод для создания нового напоминания. - -При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. -При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. -Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. -У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. -""" - client = await self.get_client() - async with client: - response = await client.post('/tasks', params=param_query) - response.raise_for_status() - return response.json() - From d7484a84e45a27470100879d9d3ef4024cc19b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 13:15:17 +0300 Subject: [PATCH 098/296] Add README --- src/generator2/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/generator2/README.md diff --git a/src/generator2/README.md b/src/generator2/README.md new file mode 100644 index 0000000..8af04b9 --- /dev/null +++ b/src/generator2/README.md @@ -0,0 +1 @@ +Запустить файл gen_class_pachca.py. Код сгенерирует функции запросов в файле api_methods.py и объявит класс PachcaBot, присвоит ему созданные функции и функцию клиента. Файл pachca.py создан для демонстрации. \ No newline at end of file From 76fb118ed9437e35b2ff94a34d2790d8fe91e0cd Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 13:29:24 +0300 Subject: [PATCH 099/296] add description key --- src/generator2/generate_pydantic_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index ff7e27a..eec9da2 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -11,12 +11,12 @@ def create_model(name: str, fields: list) -> str: if field[2]: model_code += ( f' {field[0]}: {field[1]} ' - f'= Field(..., \'{field[3]}\')\n' + f'= Field(..., description=\'{field[3]}\')\n' ) else: model_code += ( f' {field[0]}: Optional[{field[1]}] ' - f'= Field(None, \'{field[3]}\')\n' + f'= Field(None, description=\'{field[3]}\')\n' ) return model_code From fe91f0254106f902880bf2ac9e8a09fcba84f882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 13:35:12 +0300 Subject: [PATCH 100/296] Add README --- src/generator2/api_methods.py | 244 +++++++++++++++++++++++++++++ src/generator2/gen_class_pachca.py | 2 +- 2 files changed, 245 insertions(+), 1 deletion(-) diff --git a/src/generator2/api_methods.py b/src/generator2/api_methods.py index e69de29..fad9fbd 100644 --- a/src/generator2/api_methods.py +++ b/src/generator2/api_methods.py @@ -0,0 +1,244 @@ +"""Сгенерированные методы запроса.""" + + +async def get_common_methods(self, param_query=None): + """Список дополнительных полей + +Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. +""" + client = await self.get_client() + async with client: + response = await client.get('/custom_properties', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_uploads(self, param_query=None): + """Получение подписи и ключа для загрузки файла + +Возвращает параметры, необходимые для безопасной загрузки файла.""" + client = await self.get_client() + async with client: + response = await client.post('/uploads', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_direct_url(self, param_query=None): + """Получение URL для загрузки + +Отправляет запрос для получения URL для безопасной загрузки файла.""" + client = await self.get_client() + async with client: + response = await client.post('/direct_url', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_employees(self, param_query=None): + """получение актуального списка всех сотрудников компании + +Fetch a paginated list of employees with optional filtering by query. +""" + client = await self.get_client() + async with client: + response = await client.get('/users', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_employee(self, id, param_query=None): + """получение информации о сотруднике + +Метод для получения информации о сотруднике. +Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. +""" + client = await self.get_client() + async with client: + response = await client.get(f'/users/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def del_status(self, param_query=None): + """удаление своего статуса + +Параметры запроса отсутствуют +""" + client = await self.get_client() + async with client: + response = await client.delete('/profile/status', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_tag(self, id, param_query=None): + """Информация о теге + +Параметры запроса отсутствуют +""" + client = await self.get_client() + async with client: + response = await client.get(f'/group_tags/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_tags(self, param_query=None): + """Список тегов сотрудников + +Метод для получения актуального списка тегов сотрудников. +""" + client = await self.get_client() + async with client: + response = await client.get('/group_tags', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_tags_employees(self, id, param_query=None): + """получение актуального списка сотрудников тега + +Метод для получения актуального списка сотрудников тега. +""" + client = await self.get_client() + async with client: + response = await client.get(f'/group_tags/{id}/users', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_chat(self, param_query=None): + """Новая беседа или канал + +Метод для создания новой беседы или нового канала. +При создании беседы или канала вы автоматически становитесь участником.\ +""" + client = await self.get_client() + async with client: + response = await client.post('/chats', params=param_query) + response.raise_for_status() + return response.json() + + +async def get_chat(self, id, param_query=None): + """Информация о беседе или канале + +Получения информации о беседе или канале. +Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. +""" + client = await self.get_client() + async with client: + response = await client.get(f'/chats/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def post_members_to_chats(self, id, param_query=None): + """добавление пользователей в состав участников + +Метод для добавления пользователей в состав участников беседы или канала. +""" + client = await self.get_client() + async with client: + response = await client.post(f'/chats/{id}/members', params=param_query) + response.raise_for_status() + return response.json() + + +async def post_tags_to_chats(self, id, param_query=None): + """добавление тегов в состав участников беседы или канала + +Метод для добавления тегов в состав участников беседы или канала. +""" + client = await self.get_client() + async with client: + response = await client.post(f'/chats/{id}/group_tags', params=param_query) + response.raise_for_status() + return response.json() + + +async def leave_chat(self, id, param_query=None): + """Выход из беседы или канала + +Метод для самостоятельного выхода из беседы или канала.""" + client = await self.get_client() + async with client: + response = await client.delete(f'/chats/{id}/leave', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_thread(self, id, param_query=None): + """Создание нового треда + +Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. +""" + client = await self.get_client() + async with client: + response = await client.post(f'/messages/{id}/thread', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_message(self, param_query=None): + """создание нового сообщения + +Метод для отправки сообщения в беседу или канал, +личного сообщения пользователю или комментария в тред. + +При использовании entity_type: "discussion" (или просто без указания entity_type) +допускается отправка любого chat_id в поле entity_id. +То есть, сообщение можно отправить зная только идентификатор чата. +При этом, вы имеете возможность отправить сообщение в тред по его идентификатору +или личное сообщение по идентификатору пользователя. + +Для отправки личного сообщения пользователю создавать чат не требуется. +Достаточно указать entity_type: "user" и идентификатор пользователя. +Чат будет создан автоматически, если между вами ещё не было переписки. +Между двумя пользователями может быть только один личный чат. +""" + client = await self.get_client() + async with client: + response = await client.post('/messages', params=param_query) + response.raise_for_status() + return response.json() + + +async def edit_message(self, id, param_query=None): + """Редактирование сообщения + +Метод для редактирования сообщения или комментария.""" + client = await self.get_client() + async with client: + response = await client.put(f'/messages/{id}', params=param_query) + response.raise_for_status() + return response.json() + + +async def delete_message_reactions(self, id, param_query=None): + """Удаление реакции + +Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. +""" + client = await self.get_client() + async with client: + response = await client.delete(f'/messages/{id}/reactions', params=param_query) + response.raise_for_status() + return response.json() + + +async def create_task(self, param_query=None): + """Метод для создания нового напоминания. + +При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. +При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. +Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. +У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. +""" + client = await self.get_client() + async with client: + response = await client.post('/tasks', params=param_query) + response.raise_for_status() + return response.json() + diff --git a/src/generator2/gen_class_pachca.py b/src/generator2/gen_class_pachca.py index 67c3439..56bf4d2 100644 --- a/src/generator2/gen_class_pachca.py +++ b/src/generator2/gen_class_pachca.py @@ -8,7 +8,7 @@ import api_methods -TOKEN = 'Bearer l62qW6VgnJMMWx53QmwRbKEy84dzo2LhJl0Mst9m2W8' +TOKEN = 'Bearer ' async def get_client(self): From 5669a960d663ad91e4fcdb1e7715ec6f4d8c75dd Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Sun, 29 Dec 2024 17:22:56 +0500 Subject: [PATCH 101/296] refactoring_1_part --- src/openapi.yaml | 239 +++++++++++++++++++++++++++-------------------- 1 file changed, 138 insertions(+), 101 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index dec1f58..c80ad49 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -48,10 +48,13 @@ paths: parameters: - name: entity_type in: query - description: Тип сущности - участник (User) или напоминание (Task). + description: Тип сущности required: true schema: type: string + enum: + - User + - Task responses: '200': description: Успешный запрос @@ -65,22 +68,33 @@ paths: items: $ref: '#/components/schemas/QueryCommonMethods' '400': - description: BadRequest + description: Запрашиваемый ресурс не существует content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Поле не может быть пустым value: - detail: BLANK - INCLUSION: - summary: inclusion + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: description: Поле имеет непредусмотренное значение value: - detail: INCLUSION + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /uploads: post: tags: @@ -117,12 +131,12 @@ paths: - employees summary: получение актуального списка всех сотрудников компании description: | - Fetch a paginated list of employees with optional filtering by query. + Метод для получения актуального списка сотрудников вашей компании. operationId: getEmployees parameters: - name: per in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) required: false schema: type: integer @@ -138,8 +152,7 @@ paths: - name: query in: query description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) required: false schema: type: string @@ -181,19 +194,32 @@ paths: properties: data: $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден + '400': + description: Не удалось найти content: application/json: schema: - $ref: '#/components/schemas/NotFound' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /profile/status: get: tags: - status summary: получение информации о своем статусе description: | - Параметры запроса отсутствуют + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. operationId: getStatus responses: '200': @@ -210,14 +236,17 @@ paths: - status summary: новый статус description: | - Создание нового статуса. + Метод для установки себе нового статуса. operationId: putStatus requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/QueryStatus' + type: object + properties: + status: + $ref: '#/components/schemas/Status' responses: '201': description: Объект создан @@ -229,42 +258,61 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: BadRequest + description: Запрашиваемый ресурс не существует content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Обязательное поле (не может быть пустым) value: - detail: BLANK - TOO_LONG: - summary: too_long + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: description: Слишком длинное значение (пояснения вы получите в поле message) value: - detail: TOO_LONG - INVALID: - summary: invalid + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) value: - detail: INVALID - WRONG_EMOJI: - summary: wrong_emoji + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: description: Emoji статуса не может содержать значения отличные от Emoji символа value: - detail: WRONG_EMOJI + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} delete: tags: - status summary: удаление своего статуса description: | - Параметры запроса отсутствуют + Метод для удаления своего статуса. Параметры запроса отсутствуют. operationId: delStatus responses: '204': - description: Объект успешно удален, тело ответа отсутствует + description: При безошибочном выполнении запроса тело ответа отсутствует content: {} /group_tags/{id}: get: @@ -1452,33 +1500,32 @@ paths: get: tags: - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. parameters: - name: id in: path + description: Уникальный идентификатор сообщения required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 responses: '200': description: Список реакций успешно получен. @@ -1694,48 +1741,52 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - FileResponse: + Response: type: object properties: Content-Disposition: type: string + description: Используемый заголовок + default: attachment acl: type: string + description: Уровень безопасности + default: private policy: type: string + description: Уникальный policy для загрузки файла x-amz-credential: type: string + description: x-amz-credential для загрузки файла x-amz-algorithm: type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 x-amz-date: type: string + description: Уникальный x-amz-date для загрузки файла x-amz-signature: type: string + description: Уникальная подпись для загрузки файла key: type: string - direct_url: - type: string + description: Уникальный ключ для загрузки файла + FileResponse: + allOf: + - $ref: '#/components/schemas/Response' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла DirectResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string + allOf: + - $ref: '#/components/schemas/Response' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1776,27 +1827,6 @@ components: nullable: true description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true QueryCommonMethods: type: object description: получение списка актульных полей сущности. @@ -1831,18 +1861,23 @@ components: key: title: key type: string + description: Ключ параметра, в котором произошла ошибка value: title: value type: string + description: Значение ключа, которое вызвало ошибку message: title: message type: string + description: Ошибка текстом, который вы можете вывести пользователю code: title: code type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) payload: title: payload type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) Buttons: title: Message Buttons type: array @@ -1916,8 +1951,9 @@ components: title: Size type: integer buttons: + allOf: + - $ref: '#/components/schemas/Buttons' title: buttons - $ref: '#/components/schemas/Buttons' parent_message_id: title: Parent Massage Id type: integer @@ -2033,7 +2069,8 @@ components: description: Размер файла в байтах, отображаемый пользователю buttons: title: buttons - $ref: '#/components/schemas/Buttons' + allOf: + - $ref: '#/components/schemas/Buttons' thread: title: Thread type: object From 7e86daa4e7f8030a805fe74f1282a8474f9c4812 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 16:46:45 +0300 Subject: [PATCH 102/296] add enum support for pydantic models --- src/generator2/constants.py | 10 +++++++++- src/generator2/generate_pydantic_model.py | 23 ++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/generator2/constants.py b/src/generator2/constants.py index 536dec5..1514efb 100644 --- a/src/generator2/constants.py +++ b/src/generator2/constants.py @@ -1,10 +1,18 @@ -PATH_TO_YAML = './openapi.yaml' +import sys + +PATH_TO_YAML = './src/generator2/openapi.yaml' PYTHON_TYPES = { 'string': 'str', 'integer': 'int', 'boolean': 'bool', } + +ENUM_TYPES = { + 'string': 'str, Enum' if sys.version_info[1] < 11 else 'StrEnum', + 'integer': 'IntEnum', +} + HTTP_METHODS = ( 'get', 'post', 'put', 'update', 'patch', 'delete', ) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index eec9da2..a3a56ad 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -1,4 +1,4 @@ -from constants import PYTHON_TYPES +from constants import ENUM_TYPES, PYTHON_TYPES from schema_link_processor import ( replace_ref_with_schema, simple_replace_ref_with_schema, ) @@ -21,6 +21,17 @@ def create_model(name: str, fields: list) -> str: return model_code +def create_enum(name: str, enum_type: str, fields: list): + enum_class_code = f'class enum_{name}({ENUM_TYPES.get(enum_type)}):\n' + if enum_type == 'string': + for field in fields: + enum_class_code += f' {field} = \'{field}\'\n' + if enum_type == 'integer': + for field in fields: + enum_class_code += f' {name}_{field} = {field}\n' + return enum_class_code + + def look_into_schema(schema: dict) -> None: """Рекурсивно разбирает схемы. @@ -28,15 +39,23 @@ def look_into_schema(schema: dict) -> None: """ list_of_properties = [] nested_properties = [] + enum_properties = [] required_properties = [] upper_schema_name = list(schema.keys())[0] inner_schema = schema.get(upper_schema_name).get('properties') required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) + if 'enum' in inner_body: + print('+'*50, property) + enum_properties.append( + (property, inner_body.get('type'), inner_body['enum']), + ) description = inner_body.get('description', 'No docstring provided') property_type = ( PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) + if 'enum' in inner_body: + property_type = f'enum_{property}' if property_type == 'object': property_type = property.capitalize() if property_type == 'array': @@ -76,4 +95,6 @@ def look_into_schema(schema: dict) -> None: look_into_schema(replace_ref_with_schema( {nested.capitalize(): inner_schema.get(nested)}), ) + for enum_class in enum_properties: + print(create_enum(*enum_class)) print(create_model(upper_schema_name, list_of_properties)) From 25de8ec650b087d0f5d8da592fc3d65ac6de8e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 17:26:17 +0300 Subject: [PATCH 103/296] fixed/base_url --- src/generator1/requirements.txt | 10 +++-- src/generator1/script.py | 57 +++++++++++++++++++----- src/generator1/templates/client.py.jinja | 7 ++- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index 530696c..ee90ff3 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -2,20 +2,22 @@ annotated-types==0.7.0 anyio==4.7.0 attrs==24.3.0 certifi==2024.12.14 -click==8.1.8 +click==8.1.7 +colorama==0.4.6 h11==0.14.0 httpcore==1.0.7 httpx==0.27.2 idna==3.10 -Jinja2==3.1.5 +Jinja2==3.1.4 markdown-it-py==3.0.0 MarkupSafe==3.0.2 mdurl==0.1.2 -openapi-python-client==0.23.0 +openapi-python-client==0.22.0 pydantic==2.10.4 pydantic_core==2.27.2 Pygments==2.18.0 python-dateutil==2.9.0.post0 +PyYAML==6.0.2 rich==13.9.4 ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 @@ -23,5 +25,5 @@ ruff==0.8.4 shellingham==1.5.4 six==1.17.0 sniffio==1.3.1 -typer==0.15.1 +typer==0.13.1 typing_extensions==4.12.2 diff --git a/src/generator1/script.py b/src/generator1/script.py index 5a140e3..9a504f9 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,5 +1,7 @@ import ast import os +import yaml +import subprocess from jinja2 import Environment, FileSystemLoader @@ -42,19 +44,50 @@ def get_all_api_functions_and_imports(api_dir): return all_functions, all_imports -api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -endpoints, imports = get_all_api_functions_and_imports(api_dir) +def create_modified_openapi_yaml(input_path, output_path): + with open(input_path, "r", encoding="utf-8") as file: + openapi_data = yaml.safe_load(file) + base_url = openapi_data.get("servers", [{}])[0].get("url") + openapi_data["x-base-url"] = base_url + + with open(output_path, "w", encoding="utf-8") as file: + yaml.dump(openapi_data, file) + + return base_url + + +def generate_client(openapi_path, templates_path): + command = [ + "openapi-python-client", + "generate", + "--path", openapi_path, + "--custom-template-path", templates_path, + "--overwrite" + ] + subprocess.run(command, check=True) -env = Environment( - loader=FileSystemLoader('templates') -) -client_template = env.get_template('client.py.jinja') +def process_generated_client(api_dir, client_template_path, client_output_path, base_url): + endpoints, imports = get_all_api_functions_and_imports(api_dir) -client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' + env = Environment(loader=FileSystemLoader('templates')) + client_template = env.get_template(client_template_path) + + with open(client_output_path, mode='w', encoding="utf-8") as file: + # Объединяем импорты в одну строку + unique_imports = list(set(imports)) # Убираем дубликаты + file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл + file.write(client_template.render(endpoints=endpoints, base_url=base_url)) + + +openapi_input_path = "openapi.yaml" +openapi_modified_path = "openapi_modified.yaml" +templates_path = "./templates" +api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" +client_template_name = "client.py.jinja" +client_output_path = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" -with open(client_path, mode='w', encoding="utf-8") as file: - # Объединяем импорты в одну строку - unique_imports = list(set(imports)) # Убираем дубликаты - file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл - file.write(client_template.render(endpoints=endpoints)) +# Выполнение шагов +base_url = create_modified_openapi_yaml(openapi_input_path, openapi_modified_path) +generate_client(openapi_modified_path, templates_path) +process_generated_client(api_dir, client_template_name, client_output_path, base_url) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index c11a384..ee735e6 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -40,8 +40,8 @@ class Client: {% macro attributes() %} raise_on_unexpected_status: bool = field(default=False, kw_only=True) _base_url: str = field( - default="https://api.pachca.com/api/shared/v1", - kw_only=True, + default="{{ base_url }}", + kw_only=True, alias="base_url" ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") @@ -158,7 +158,7 @@ class AuthenticatedClient: raise_on_unexpected_status: bool = field(default=False, kw_only=True) _base_url: str = field( - default="https://api.pachca.com/api/shared/v1", + default="{{ base_url }}", kw_only=True, alias="base_url" ) @@ -275,4 +275,3 @@ class Pachca: {{ endpoint | indent(4, first=Fasle) }} {% endfor %} {% endif %} - \ No newline at end of file From ea833c84c6e5abc70baf430c0398a42c504a384c Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 29 Dec 2024 18:59:42 +0300 Subject: [PATCH 104/296] add dot in script --- src/generator1/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generator1/script.py b/src/generator1/script.py index 5a140e3..0782cd9 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -46,7 +46,7 @@ def get_all_api_functions_and_imports(api_dir): endpoints, imports = get_all_api_functions_and_imports(api_dir) env = Environment( - loader=FileSystemLoader('templates') + loader=FileSystemLoader('templates'), ) client_template = env.get_template('client.py.jinja') From fe956d27ce91e6efe320031ad017e4c37d7ea09f Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Sun, 29 Dec 2024 21:15:58 +0500 Subject: [PATCH 105/296] refactoring_2_part --- src/openapi.yaml | 392 +++++++++++++++++++++++++++-------------------- 1 file changed, 230 insertions(+), 162 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index c80ad49..f8d954c 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -68,7 +68,7 @@ paths: items: $ref: '#/components/schemas/QueryCommonMethods' '400': - description: Запрашиваемый ресурс не существует + description: Пояснения ошибки content: application/json: schema: @@ -121,7 +121,7 @@ paths: content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: '204': description: Успешный запрос. @@ -195,7 +195,7 @@ paths: data: $ref: '#/components/schemas/Employee' '400': - description: Не удалось найти + description: Пояснения ошибки content: application/json: schema: @@ -258,7 +258,7 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: Запрашиваемый ресурс не существует + description: Пояснения ошибки content: application/json: schema: @@ -339,38 +339,25 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: @@ -407,43 +394,25 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + inclusion: + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: inclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -487,11 +456,24 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /chats: post: tags: @@ -509,7 +491,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -521,7 +503,7 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: @@ -557,16 +539,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -674,14 +646,14 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -701,16 +673,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -765,8 +727,8 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: @@ -823,13 +785,70 @@ paths: '201': description: Пользователи добавлены '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -867,47 +886,116 @@ paths: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/leave: delete: tags: - talk and channel participants operationId: leaveChat - summary: 'Выход из беседы или канала' + summary: выход из беседы или канала description: |- - Метод для самостоятельного выхода из беседы или канала. + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ parameters: - name: id in: path required: true - description: 'Уникальный идентификатор беседы или канала.' + description: Уникальный идентификатор беседы или канала. schema: type: integer responses: '200': - description: 'Успешно отписан. Тело ответа отсутствует' + description: При безошибочном выполнении запроса тело ответа отсутствуе '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} /messages/{id}/thread: post: tags: @@ -1248,9 +1336,9 @@ paths: code: not_found put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -2163,60 +2251,7 @@ components: type: string payload: type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2242,6 +2277,39 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. From dc928c947706270b1a028550c0f43c05758cc1db Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Sun, 29 Dec 2024 21:24:37 +0500 Subject: [PATCH 106/296] refactoring_2_part_ver2 --- src/openapi.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index f8d954c..4627f01 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -404,14 +404,14 @@ paths: errors: $ref: '#/components/schemas/Errors' examples: - inclusion: + exclusion: description: Поле имеет непредусмотренное значение value: errors: - key: string value: string message: message - code: inclusion + code: exclusion payload: {} /group_tags/{id}/users: get: @@ -465,14 +465,14 @@ paths: errors: $ref: '#/components/schemas/Errors' examples: - inclusion: + exclusion: description: Поле имеет непредусмотренное значение value: errors: - key: string value: string message: message - code: inclusion + code: exclusion payload: {} /chats: post: From 2eccebba60d779bbe6c33efe29274f396614806e Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 29 Dec 2024 19:36:48 +0300 Subject: [PATCH 107/296] added base_url throught parse yaml --- src/generator1/openapi_modified.yaml | 3162 ++++++++++++++++++++++ src/generator1/script.py | 156 +- src/generator1/templates/client.py.jinja | 2 +- 3 files changed, 3276 insertions(+), 44 deletions(-) create mode 100644 src/generator1/openapi_modified.yaml diff --git a/src/generator1/openapi_modified.yaml b/src/generator1/openapi_modified.yaml new file mode 100644 index 0000000..90c74d0 --- /dev/null +++ b/src/generator1/openapi_modified.yaml @@ -0,0 +1,3162 @@ +components: + schemas: + BadRequest: + properties: + error: + type: string + message: + type: string + type: object + BaseEmployee: + description: "\u0411\u0430\u0437\u043E\u0432\u044B\u0439 \u043A\u043B\u0430\u0441\ + \u0441 \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0430." + properties: + bot: + description: "\u0422\u0438\u043F: \u043F\u043E\u043B\u044C\u0437\u043E\u0432\ + \u0430\u0442\u0435\u043B\u044C (false) \u0438\u043B\u0438 \u0431\u043E\ + \u0442 (true)\n" + type: boolean + custom_properties: + description: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\ + \u044C\u043D\u044B\u0435 \u043F\u043E\u043B\u044F \u0441\u043E\u0442\u0440\ + \u0443\u0434\u043D\u0438\u043A\u0430" + items: + properties: + data_type: + description: "\u0422\u0438\u043F \u043F\u043E\u043B\u044F (string,\ + \ number, date \u0438\u043B\u0438 link)" + type: string + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044F" + type: integer + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043F\ + \u043E\u043B\u044F" + type: string + value: + description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435" + type: string + type: object + type: array + department: + description: "\u0414\u0435\u043F\u0430\u0440\u0442\u0430\u043C\u0435\u043D\ + \u0442" + type: string + email: + description: "\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\ + \u044F \u043F\u043E\u0447\u0442\u0430" + type: string + first_name: + description: "\u0418\u043C\u044F" + type: string + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\ + \u0435\u043B\u044F" + example: 1 + type: integer + invite_status: + description: "\u0421\u0442\u0430\u0442\u0443\u0441 \u043F\u0440\u0438\u0433\ + \u043B\u0430\u0448\u0435\u043D\u0438\u044F: confirmed (\u043F\u0440\u0438\ + \u043D\u044F\u0442\u043E), sent (\u043E\u0442\u043F\u0440\u0430\u0432\u043B\ + \u0435\u043D\u043E)\n" + type: string + last_name: + description: "\u0424\u0430\u043C\u0438\u043B\u0438\u044F" + type: string + list_tags: + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0442\u0435\u0433\u043E\ + \u0432, \u043F\u0440\u0438\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0445\ + \ \u043A \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0443" + items: + type: string + type: array + nickname: + description: "\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\ + \u0430\u0442\u0435\u043B\u044F" + type: string + phone_number: + description: "\u0422\u0435\u043B\u0435\u0444\u043E\u043D" + type: string + role: + description: "\u0423\u0440\u043E\u0432\u0435\u043D\u044C \u0434\u043E\u0441\ + \u0442\u0443\u043F\u0430: admin (\u0430\u0434\u043C\u0438\u043D\u0438\u0441\ + \u0442\u0440\u0430\u0442\u043E\u0440), user (\u0441\u043E\u0442\u0440\u0443\ + \u0434\u043D\u0438\u043A), multi_guest (\u043C\u0443\u043B\u044C\u0442\ + \u0438-\u0433\u043E\u0441\u0442\u044C)\n" + type: string + suspended: + description: "\u0414\u0435\u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0438\ + \u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ + \u044F. \u041F\u0440\u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0438\ + \ true \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ + \u044C \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0434\u0435\u0430\ + \u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\ + \u043C.\n" + type: boolean + type: object + Buttons: + items: + items: + minProperties: 2 + properties: + data: + maxLength: 255 + title: Data + type: string + text: + maxLength: 255 + title: Text + type: string + url: + title: Url + type: string + required: + - text + title: Button + type: object + maxItems: 8 + title: Row Buttons + type: array + maxItems: 100 + title: Message Buttons + type: array + Chat: + description: "\u0411\u0435\u0441\u0435\u0434\u0430 \u0438\u043B\u0438 \u043A\ + \u0430\u043D\u0430\u043B" + properties: + channel: + description: "\u0422\u0438\u043F: \u0431\u0435\u0441\u0435\u0434\u0430 (false)\ + \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B (true)" + example: true + type: boolean + created_at: + description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F\ + \ \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u0431\u0435\u0441\u0435\ + \u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430 (ISO-8601,\ + \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" + example: '2021-08-28T15:56:53.000Z' + format: date-time + type: string + group_tag_ids: + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ + \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u0442\ + \u0435\u0433\u043E\u0432, \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\ + \u043E\u0432" + example: [] + items: + type: integer + type: array + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438\ + \ \u043A\u0430\u043D\u0430\u043B\u0430" + example: 334 + type: integer + last_message_at: + description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F\ + \ \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u043B\ + \u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u044F \u0432 \u0431\u0435\u0441\u0435\u0434\u0435/\u043A\u0430\ + \u043D\u0430\u043B\u0435 (ISO-8601, UTC+0) \u0432 \u0444\u043E\u0440\u043C\ + \u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" + example: '2021-08-28T15:58:13.000Z' + format: date-time + type: string + meet_room_url: + description: "\u0421\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0412\u0438\ + \u0434\u0435\u043E\u0447\u0430\u0442" + example: https://meet.pachca.com/aqua-94bb21b5 + type: string + member_ids: + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ + \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u043F\ + \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439\ + , \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u0432" + example: + - 185 + - 186 + - 187 + items: + type: integer + type: array + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" + example: "\U0001F93F aqua" + type: string + owner_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\ + \u0435\u043B\u044F, \u0441\u043E\u0437\u0434\u0430\u0432\u0448\u0435\u0433\ + \u043E \u0431\u0435\u0441\u0435\u0434\u0443 \u0438\u043B\u0438 \u043A\u0430\ + \u043D\u0430\u043B" + example: 185 + type: integer + public: + description: "\u0414\u043E\u0441\u0442\u0443\u043F: \u0437\u0430\u043A\u0440\ + \u044B\u0442\u044B\u0439 (false) \u0438\u043B\u0438 \u043E\u0442\u043A\ + \u0440\u044B\u0442\u044B\u0439 (true)" + example: false + type: boolean + type: object + CreateMessage: + properties: + buttons: + $ref: '#/components/schemas/Buttons' + title: buttons + content: + title: Content + type: string + entity_id: + title: Entity Id + type: integer + entity_type: + default: discussion + enum: + - discussion + - user + - thread + title: Entity Type + type: string + files: + items: + properties: + file_type: + enum: + - file + - image + title: File Type + type: string + key: + title: Key + type: string + name: + title: Name + type: string + size: + title: Size + type: integer + required: + - key + - name + - file_type + - size + type: object + title: Files + type: array + link_preview: + default: false + title: Link Preview + type: boolean + parent_message_id: + default: null + nullable: true + title: Parent Massage Id + type: integer + skip_invite_mentions: + default: false + title: Skip Invite Mentions + type: boolean + required: + - entity_id + - content + type: object + DirectResponse: + properties: + Content-Disposition: + type: string + acl: + type: string + file: + type: string + key: + type: string + policy: + type: string + x-amz-algorithm: + type: string + x-amz-credential: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + type: object + EditMessages: + description: "\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\ + \u044F \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0432\u0430\ + \u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0437\ + \u043D\u0430\u0442\u044C \u0435\u0433\u043E id \u0438 \u0443\u043A\u0430\u0437\ + \u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\u0440\u043E\ + \u0441\u0430." + properties: + buttons: + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0441\u0442\u0440\u043E\ + \u043A, \u043A\u0430\u0436\u0434\u0430\u044F \u0438\u0437 \u043A\u043E\ + \u0442\u043E\u0440\u044B\u0445 \u043F\u0440\u0435\u0434\u0441\u0442\u0430\ + \u0432\u043B\u0435\u043D\u0430 \u043C\u0430\u0441\u0441\u0438\u0432\u043E\ + \u043C \u043A\u043D\u043E\u043F\u043E\u043A. \u041F\u043E\u0434\u0440\u043E\ + \u0431\u043D\u0435\u0435 \u043E \u0442\u043E\u043C, \u043A\u0430\u043A\ + \ \u0444\u043E\u0440\u043C\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\ + \u0442\u0440\u043E\u043A\u0438 \u043A\u043D\u043E\u043F\u043E\u043A \u0438\ + \ \u043A\u0430\u043A\u0438\u0435 \u0435\u0441\u0442\u044C \u043E\u0433\ + \u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u044F \u0432\u044B \u043C\ + \u043E\u0436\u0435\u0442\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\ + \u0442\u044C \u0432 \u0441\u0442\u0430\u0442\u044C\u0435. \u0414\u043B\ + \u044F \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u043A\u043D\u043E\ + \u043F\u043E\u043A \u0443 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ + \u044F \u043F\u0440\u0438\u0448\u043B\u0438\u0442\u0435 \u043F\u0443\u0441\ + \u0442\u043E\u0439 \u043C\u0430\u0441\u0441\u0438\u0432." + items: + items: + properties: + data: + description: "\u0414\u0430\u043D\u043D\u044B\u0435, \u043A\u043E\ + \u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442\ + \ \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u044B\ + \ \u0432 \u0438\u0441\u0445\u043E\u0434\u044F\u0449\u0435\u043C\ + \ \u0432\u0435\u0431\u0445\u0443\u043A\u0435 \u043F\u043E \u043D\ + \u0430\u0436\u0430\u0442\u0438\u044E \u043A\u043D\u043E\u043F\u043A\ + \u0438" + type: string + text: + description: "\u0422\u0435\u043A\u0441\u0442, \u043E\u0442\u043E\ + \u0431\u0440\u0430\u0436\u0430\u0435\u043C\u044B\u0439 \u043D\u0430\ + \ \u043A\u043D\u043E\u043F\u043A\u0435 \u043F\u043E\u043B\u044C\ + \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E" + type: string + url: + description: "\u0421\u0441\u044B\u043B\u043A\u0430, \u043A\u043E\ + \u0442\u043E\u0440\u0430\u044F \u0431\u0443\u0434\u0435\u0442\ + \ \u043E\u0442\u043A\u0440\u044B\u0442\u0430 \u043F\u043E \u043D\ + \u0430\u0436\u0430\u0442\u0438\u044E \u043A\u043D\u043E\u043F\u043A\ + \u0438" + type: string + type: object + type: array + type: array + content: + default: "\u0422\u0435\u043A\u0441\u0442 \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u044F" + description: "\u0422\u0435\u043A\u0441\u0442 \u0441\u043E\u043E\u0431\u0449\ + \u0435\u043D\u0438\u044F" + type: string + files: + properties: + file_type: + enum: + - file + - image + type: string + key: + description: "\u041F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\ + \u0443, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043D\u044B\u0439\ + \ \u0432 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0435\ + \ \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0444\u0430\u0439\ + \u043B\u0430 (\u043A\u0430\u0436\u0434\u044B\u0439 \u0444\u0430\u0439\ + \u043B \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0441\u043E\u043E\ + \u0431\u0449\u0435\u043D\u0438\u0438 \u0434\u043E\u043B\u0436\u0435\ + \u043D \u0438\u043C\u0435\u0442\u044C \u0441\u0432\u043E\u0439 \u0443\ + \u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 key, \u043D\ + \u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\ + \u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\ + \u043D\u0438\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u0438 \u0442\ + \u043E\u0433\u043E \u0436\u0435 key \u0432 \u0440\u0430\u0437\u043D\ + \u044B\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + \u0445)" + type: string + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0444\ + \u0430\u0439\u043B\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0435\ + \ \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0442\u043E\ + \u0431\u0440\u0430\u0436\u0430\u0442\u044C \u043F\u043E\u043B\u044C\ + \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E (\u0440\u0435\u043A\ + \u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u043F\ + \u0438\u0441\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\u0435\ + \ \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435\ + \u043C)" + type: string + size: + default: 1234 + description: "\u0420\u0430\u0437\u043C\u0435\u0440 \u0444\u0430\u0439\ + \u043B\u0430 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445, \u043E\u0442\ + \u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u044B\u0439 \u043F\ + \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E" + type: integer + type: object + type: object + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - description: "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u043D\u044B\ + \u0439 \u043A\u043B\u0430\u0441\u0441 \u0441\u043E\u0442\u0440\u0443\u0434\ + \u043D\u0438\u043A\u0430." + properties: + created_at: + description: "\u0414\u0430\u0442\u0430 \u0441\u043E\u0437\u0434\u0430\u043D\ + \u0438\u044F (ISO-8601, UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\ + \u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ\n" + format: date-time + type: string + image_url: + description: "\u0421\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0441\ + \u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0430\u0432\u0430\ + \u0442\u0430\u0440\u043A\u0438" + nullable: true + type: string + time_zone: + description: "\u0427\u0430\u0441\u043E\u0432\u043E\u0439 \u043F\u043E\u044F\ + \u0441 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ + \u044F" + type: string + title: + description: "\u0414\u043E\u043B\u0436\u043D\u043E\u0441\u0442\u044C" + type: string + user_status: + $ref: '#/components/schemas/Status' + type: object + Errors: + items: + properties: + code: + title: code + type: string + key: + title: key + type: string + message: + title: message + type: string + payload: + title: payload + type: object + value: + title: value + type: string + title: Error + type: object + title: Errors + type: array + ErrorsCode: + description: Bad Request + properties: + code: + type: string + key: + type: string + message: + type: string + payload: + type: object + value: + type: string + type: object + FileResponse: + properties: + Content-Disposition: + type: string + acl: + type: string + direct_url: + type: string + key: + type: string + policy: + type: string + x-amz-algorithm: + type: string + x-amz-credential: + type: string + x-amz-date: + type: string + x-amz-signature: + type: string + type: object + Message: + properties: + buttons: + $ref: '#/components/schemas/Buttons' + title: buttons + chat_id: + title: Chat Id + type: integer + content: + title: Content + type: string + created_at: + format: date-time + title: Created At + type: string + entity_id: + title: Entity Id + type: integer + entity_type: + default: discussion + enum: + - discussion + - user + - thread + title: Entity Type + type: string + files: + items: + properties: + file_type: + enum: + - file + - image + title: File Type + type: string + id: + title: Id + type: integer + key: + description: "\u041F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\ + \u0443, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043D\u044B\u0439\ + \ \u0432 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0435\ + \ \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0444\u0430\u0439\ + \u043B\u0430 (\u043A\u0430\u0436\u0434\u044B\u0439 \u0444\u0430\u0439\ + \u043B \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0441\u043E\u043E\ + \u0431\u0449\u0435\u043D\u0438\u0438 \u0434\u043E\u043B\u0436\u0435\ + \u043D \u0438\u043C\u0435\u0442\u044C \u0441\u0432\u043E\u0439 \u0443\ + \u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 key, \u043D\ + \u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\ + \u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\ + \u043D\u0438\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u0438 \u0442\ + \u043E\u0433\u043E \u0436\u0435 key \u0432 \u0440\u0430\u0437\u043D\ + \u044B\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + \u0445)" + title: Key + type: string + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0444\ + \u0430\u0439\u043B\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0435\ + \ \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0442\ + \u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C \u043F\u043E\u043B\ + \u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E (\u0440\u0435\ + \u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F\ + \ \u043F\u0438\u0441\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\ + \u0435 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\ + \u0435\u043C)" + title: Name + type: string + url: + description: "\u0420\u0430\u0437\u043C\u0435\u0440 \u0444\u0430\u0439\ + \u043B\u0430 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445, \u043E\ + \u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u044B\u0439\ + \ \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ + \u044E" + title: Url + type: string + type: object + title: Files + type: array + forwarding: + default: null + nullable: true + properties: + author_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430, \u0432 \u043A\u043E\ + \u0442\u043E\u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\u0438\ + \u0442\u0441\u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\ + \u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ + \u0438\u0435" + title: Author Id + type: integer + original_chat_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430, \u0432 \u043A\u043E\ + \u0442\u043E\u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\u0438\ + \u0442\u0441\u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\ + \u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ + \u0438\u0435" + title: Original Chat Id + type: integer + original_created_at: + description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\ + \u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043E\u0440\ + \u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u043E\u0433\u043E\ + \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F (ISO-8601,\ + \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" + title: Original Created At + type: integer + original_message_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u043E\u0440\u0438\u0433\u0438\u043D\u0430\ + \u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\ + \u0435\u043D\u0438\u044F" + title: Origin Message Id + type: integer + original_thread_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u0442\u0440\u0435\u0434\u0430, \u0432 \u043A\ + \u043E\u0442\u043E\u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\ + \u0438\u0442\u0441\u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\ + \u043B\u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u0435. \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\ + \u0435\u0442\u0441\u044F \u043A\u0430\u043A null, \u0435\u0441\u043B\ + \u0438 \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\ + \u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + \ \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A\ + \u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0435\u043C\ + \ \u0432 \u0442\u0440\u0435\u0434\u0435." + nullable: true + title: Original Thread Id + type: integer + original_thread_message_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ + \u0438\u044F, \u043A \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443\ + \ \u0431\u044B\u043B \u0441\u043E\u0437\u0434\u0430\u043D \u0442\u0440\ + \u0435\u0434, \u0432 \u043A\u043E\u0442\u043E\u0440\u043E\u043C \u043D\ + \u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u043E\u0440\u0438\ + \u0433\u0438\u043D\u0430\u043B\u044C\u043D\u043E\u0435 \u0441\u043E\ + \u043E\u0431\u0449\u0435\u043D\u0438\u0435. \u0412\u043E\u0437\u0432\ + \u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A\ + \ null, \u0435\u0441\u043B\u0438 \u043E\u0440\u0438\u0433\u0438\u043D\ + \u0430\u043B\u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\ + \u0435\u043D\u0438\u0435 \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\ + \u0442\u0441\u044F \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\ + \u0440\u0438\u0435\u043C \u0432 \u0442\u0440\u0435\u0434\u0435." + nullable: true + title: Original Thread Message Id + type: integer + original_thread_parent_chat_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430 \u0441\u043E\u043E\ + \u0431\u0449\u0435\u043D\u0438\u044F, \u043A \u043A\u043E\u0442\u043E\ + \u0440\u043E\u043C\u0443 \u0431\u044B\u043B \u0441\u043E\u0437\u0434\ + \u0430\u043D \u0442\u0440\u0435\u0434, \u0432 \u043A\u043E\u0442\u043E\ + \u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\ + \u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\ + \u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + . \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\ + \u044F \u043A\u0430\u043A null, \u0435\u0441\u043B\u0438 \u043E\u0440\ + \u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u043E\u0435 \u0441\ + \u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\u0435 \u044F\ + \u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A\u043E\u043C\u043C\ + \u0435\u043D\u0442\u0430\u0440\u0438\u0435\u043C \u0432 \u0442\u0440\ + \u0435\u0434\u0435." + nullable: true + title: Original Thread Parent Chat Id + type: integer + title: Forwarding + type: object + id: + title: Id + type: integer + parent_message_id: + default: null + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + , \u043A \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u043D\u0430\ + \u043F\u0438\u0441\u0430\u043D \u043E\u0442\u0432\u0435\u0442. \u0412\u043E\ + \u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\ + \u043A null, \u0435\u0441\u043B\u0438 \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u0435 \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\ + \u044F \u043E\u0442\u0432\u0435\u0442\u043E\u043C." + nullable: true + title: Parent Massage Id + type: integer + thread: + default: null + nullable: true + properties: + chat_id: + title: Chat Id + type: integer + id: + title: Id + type: integer + title: Thread + type: object + user_id: + title: User Id + type: integer + type: object + NotFound: + description: "\u041E\u0431\u044A\u0435\u043A\u0442 \u043D\u0435 \u043D\u0430\ + \u0439\u0434\u0435\u043D" + properties: + detail: + description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043E\u0448\ + \u0438\u0431\u043A\u0438" + example: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u043D\u0435\ + \ \u043D\u0430\u0439\u0434\u0435\u043D\u0430." + type: string + type: object + QueryChat: + description: "\u0421\u043E\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043E\u0431\ + \u044A\u0435\u043A\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\ + \u0432 \u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0435\u043C\u043E\u0439\ + \ \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\ + \u0430\u043B\u0430" + properties: + channel: + description: "\u0422\u0438\u043F: \u0431\u0435\u0441\u0435\u0434\u0430 (\u043F\ + \u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E, false)\ + \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B (true)" + example: true + type: boolean + member_ids: + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ + \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u043F\ + \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439\ + , \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\u0442\u0430\u043D\u0443\ + \u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u0430\u043C\u0438" + example: + - 186 + - 187 + items: + type: integer + type: array + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" + example: "\U0001F93F aqua" + type: string + public: + description: "\u0414\u043E\u0441\u0442\u0443\u043F: \u0437\u0430\u043A\u0440\ + \u044B\u0442\u044B\u0439 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\ + \u043D\u0438\u044E, false) \u0438\u043B\u0438 \u043E\u0442\u043A\u0440\ + \u044B\u0442\u044B\u0439 (true)" + example: false + type: boolean + required: + - name + type: object + QueryCommonMethods: + description: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0441\u043F\ + \u0438\u0441\u043A\u0430 \u0430\u043A\u0442\u0443\u043B\u044C\u043D\u044B\u0445\ + \ \u043F\u043E\u043B\u0435\u0439 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\ + \u0438." + properties: + data_type: + description: "\u0442\u0438\u043F \u043F\u043E\u043B\u044F (string, number,\ + \ date \u0438\u043B\u0438 link)" + example: number + type: string + id: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\ + \u043B\u044F" + example: 1 + type: integer + name: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u043F\u043E\u043B\u044F" + example: "\u0414\u0430\u0442\u0430 \u0440\u043E\u0436\u0434\u0435\u043D\u0438\ + \u044F" + type: string + type: object + QueryStatus: + properties: + status: + description: "\u0421\u043E\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043E\ + \u0431\u044A\u0435\u043A\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\ + \u0440\u043E\u0432 \u043D\u043E\u0432\u043E\u0433\u043E \u0441\u0442\u0430\ + \u0442\u0443\u0441\u0430" + properties: + emoji: + description: "Emoji \u0441\u0438\u043C\u0432\u043E\u043B \u0441\u0442\ + \u0430\u0442\u0443\u0441\u0430" + type: string + expires_at: + description: "\u0421\u0440\u043E\u043A \u0434\u0435\u0439\u0441\u0442\ + \u0432\u0438\u044F \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (ISO-8601,\ + \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" + format: date-time + nullable: true + type: string + title: + description: "\u0422\u0435\u043A\u0441\u0442 \u0441\u0442\u0430\u0442\ + \u0443\u0441\u0430" + type: string + required: + - emoji + - title + type: object + type: object + Reaction: + properties: + code: + description: "Emoji \u0441\u0438\u043C\u0432\u043E\u043B \u0440\u0435\u0430\ + \u043A\u0446\u0438\u0438.\n" + type: string + created_at: + description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F\ + \ \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0440\u0435\ + \u0430\u043A\u0446\u0438\u0438 (ISO-8601, UTC+0) \u0432 \u0444\u043E\u0440\ + \u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ.\n" + format: date-time + type: string + user_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\ + \u0435\u043B\u044F, \u043E\u0441\u0442\u0430\u0432\u0438\u0432\u0448\u0435\ + \u0433\u043E \u0440\u0435\u0430\u043A\u0446\u0438\u044E.\n" + type: integer + type: object + Status: + description: "\u0421\u0442\u0430\u0442\u0443\u0441. \u0412\u043E\u0437\u0432\ + \u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A null,\ + \ \u0435\u0441\u043B\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u043D\u0435\ + \ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D." + nullable: true + properties: + emoji: + description: "Emoji \u0441\u0438\u043C\u0432\u043E\u043B \u0441\u0442\u0430\ + \u0442\u0443\u0441\u0430" + type: string + expires_at: + description: "\u0421\u0440\u043E\u043A \u0436\u0438\u0437\u043D\u0438 \u0441\ + \u0442\u0430\u0442\u0443\u0441\u0430 (ISO-8601, UTC+0) \u0432 \u0444\u043E\ + \u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ. \u0412\u043E\u0437\ + \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A\ + \ null, \u0435\u0441\u043B\u0438 \u0441\u0440\u043E\u043A \u043D\u0435\ + \ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D.\n" + format: date-time + nullable: true + type: string + title: + description: "\u0422\u0435\u043A\u0441\u0442 \u0441\u0442\u0430\u0442\u0443\ + \u0441\u0430" + type: string + type: object + Tag: + description: "\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\ + \u044F \u0442\u0435\u0433\u0430 \u0432\u0430\u043C \u043D\u0435\u043E\u0431\ + \u0445\u043E\u0434\u0438\u043C\u043E \u0437\u043D\u0430\u0442\u044C \u0435\ + \u0433\u043E id \u0438 \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0433\ + \u043E \u0432 URL \u0437\u0430\u043F\u0440\u043E\u0441\u0430." + properties: + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0442\u0435\u0433\u0430" + type: integer + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0442\u0435\ + \u0433\u0430" + type: string + users_count: + description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432,\ + \ \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0438\u043C\u0435\u044E\u0442\ + \ \u044D\u0442\u043E\u0442 \u0442\u0435\u0433" + type: integer + type: object + securitySchemes: + bearerAuth: + scheme: bearer + type: http +info: + description: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\ + \u044F \u043A \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u043C\u0443 API \u043F\ + \u0430\u0447\u043A\u0438" + title: PachcaAPI - OpenAPI 3.0 + version: 3.0.3 +openapi: 3.0.3 +paths: + /chats: + get: + description: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u043F\ + \u0438\u0441\u043A\u0430 \u0431\u0435\u0441\u0435\u0434 \u0438 \u043A\u0430\ + \u043D\u0430\u043B\u043E\u0432 \u043F\u043E \u0437\u0430\u0434\u0430\u043D\ + \u043D\u044B\u043C \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\ + ." + operationId: getChats + parameters: + - description: "\u0421\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u043F\ + \u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0441\u043E\u0440\u0442\u0438\ + \u0440\u043E\u0432\u043A\u0438 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\ + \u0435\u0439 \u0432\u044B\u0431\u043E\u0440\u043A\u0438.\n\u0412\u0430\u0440\ + \u0438\u0430\u043D\u0442\u044B \u0437\u043D\u0430\u0447\u0435\u043D\u0438\ + \u0439: \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E\ + \ desc (\u043F\u043E \u0443\u0431\u044B\u0432\u0430\u043D\u0438\u044E) \u0438\ + \u043B\u0438 asc (\u043F\u043E \u0432\u043E\u0437\u0440\u0430\u0441\u0442\ + \u0430\u043D\u0438\u044E).\n\u041D\u0430 \u0434\u0430\u043D\u043D\u044B\u0439\ + \ \u043C\u043E\u043C\u0435\u043D\u0442 \u0441\u043E\u0440\u0442\u0438\u0440\ + \u043E\u0432\u043A\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430\ + \ \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E \u043F\u043E\u043B\u044E\ + \ ({field}) id (\u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434 \u0438 \u043A\u0430\u043D\ + \u0430\u043B\u043E\u0432).\n" + in: query + name: sort[id] + required: false + schema: + default: desc + enum: + - desc + - asc + type: string + - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ + \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ + \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ + \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 25, \u043C\u0430\u043A\u0441\ + \u0438\u043C\u0443\u043C 50)" + in: query + name: per + required: false + schema: + default: 25 + maximum: 50 + type: integer + - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ + \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ + \u0430\u043D\u0438\u044E 1)" + in: query + name: page + required: false + schema: + default: 1 + type: integer + - description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440, \u043A\u043E\ + \u0442\u043E\u0440\u044B\u0439 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\ + \u0442 \u0437\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\ + \u0442\u044C \u0438 \u0432\u044B\u0431\u043E\u0440\u043A\u0443 \u0431\u0435\ + \u0441\u0435\u0434 \u0438 \u043A\u0430\u043D\u0430\u043B\u043E\u0432 \u0434\ + \u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\ + \u043B\u044F.\n\u0412\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u0437\u043D\ + \u0430\u0447\u0435\u043D\u0438\u0439: \u043F\u043E \u0443\u043C\u043E\u043B\ + \u0447\u0430\u043D\u0438\u044E is_member (\u0431\u0435\u0441\u0435\u0434\ + \u044B \u0438 \u043A\u0430\u043D\u0430\u043B\u044B, \u0433\u0434\u0435 \u043F\ + \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u044F\ + \u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0443\u0447\u0430\u0441\u0442\ + \u043D\u0438\u043A\u043E\u043C)\n\u0438\u043B\u0438 public (\u0432\u0441\ + \u0435 \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 \u0431\u0435\u0441\ + \u0435\u0434\u044B \u0438 \u043A\u0430\u043D\u0430\u043B\u044B \u043A\u043E\ + \u043C\u043F\u0430\u043D\u0438\u0438, \u0432\u043D\u0435 \u0437\u0430\u0432\ + \u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438 \u043E\u0442 \u0443\u0447\ + \u0430\u0441\u0442\u0438\u044F \u0432 \u043D\u0438\u0445 \u043F\u043E\u043B\ + \u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F).\n" + in: query + name: availability + required: false + schema: + default: is_member + enum: + - is_member + - public + type: string + - description: "\u0424\u0438\u043B\u044C\u0442\u0440\u0430\u0446\u0438\u044F\ + \ \u043F\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0441\u043E\u0437\ + \u0434\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\ + \u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + .\n\u0411\u0443\u0434\u0443\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\ + \u0435\u043D\u044B \u0442\u0435 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\ + \u0430\u043D\u0430\u043B\u044B, \u0432\u0440\u0435\u043C\u044F \u043F\u043E\ + \u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u0437\u0434\ + \u0430\u043D\u043D\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u044F \u0432 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u043D\ + \u0435 \u0440\u0430\u043D\u044C\u0448\u0435 \u0447\u0435\u043C \u0443\u043A\ + \u0430\u0437\u0430\u043D\u043D\u043E\u0435 (\u0432 \u0444\u043E\u0440\u043C\ + \u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ).\n" + in: query + name: last_message_at_after + required: false + schema: + format: date-time + type: string + - description: "\u0424\u0438\u043B\u044C\u0442\u0440\u0430\u0446\u0438\u044F\ + \ \u043F\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0441\u043E\u0437\ + \u0434\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\ + \u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + .\n\u0411\u0443\u0434\u0443\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\ + \u0435\u043D\u044B \u0442\u0435 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\ + \u0430\u043D\u0430\u043B\u044B, \u0432\u0440\u0435\u043C\u044F \u043F\u043E\ + \u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u0437\u0434\ + \u0430\u043D\u043D\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u044F \u0432 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u043D\ + \u0435 \u043F\u043E\u0437\u0436\u0435 \u0447\u0435\u043C \u0443\u043A\u0430\ + \u0437\u0430\u043D\u043D\u043E\u0435 (\u0432 \u0444\u043E\u0440\u043C\u0430\ + \u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ).\n" + in: query + name: last_message_at_before + required: false + schema: + format: date-time + type: string + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + $ref: '#/components/schemas/Chat' + type: array + type: object + description: "\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0442\u0440\u0430\ + \u0431\u043E\u0442\u0430\u043B \u043A\u0430\u043A \u043F\u043E\u043B\u043E\ + \u0436\u0435\u043D\u043E, \u0431\u0435\u0437 \u043E\u0448\u0438\u0431\u043E\ + \u043A" + '400': + content: + application/json: + examples: + invalid: + description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u0441\u043E\ + \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ + \ \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C (\u043F\u043E\ + \u044F\u0441\u043D\u0435\u043D\u0438\u044F \u0432\u044B \u043F\ + \u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u0432 \u043F\u043E\ + \u043B\u0435 message)" + value: + errors: + - code: invalid + key: name + message: message + payload: {} + value: 1234 + too_long: + description: "\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\ + \u0438\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\ + \u0438\u0435 (\u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\ + \u044F \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\ + \u0435 \u0432 \u043F\u043E\u043B\u0435 message)" + value: + errors: + - code: too_long + key: name + message: message + payload: {} + value: long_name + schema: + properties: + errors: + $ref: '#/components/schemas/ErrorsCode' + type: object + description: "\u041D\u0435\u043F\u0440\u0438\u0435\u043C\u043B\u0435\u043C\ + \u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 (\u0447\u0430\u0441\u0442\ + \u043E \u0438\u0437-\u0437\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\ + \u0432\u0438\u044F \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ + \u043D\u043E\u0433\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\ + \u0430)" + '404': + content: + application/json: + examples: + not_found: + description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438" + value: + errors: + - code: not_found + key: string + message: message + payload: {} + value: string + schema: + properties: + errors: + $ref: '#/components/schemas/Errors' + type: object + description: "\u0417\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\ + \u043C\u044B\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043D\u0435 \u0441\ + \u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442" + '422': + content: + application/json: + examples: + invalid: + description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\ + \u0440\u043C\u0430\u0442 (\u0438\u0434\u0435\u043D\u0442\u0438\ + \u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044F\ + \ \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0435\ + \ \u0432 \u043F\u043E\u043B\u0435 payload)" + value: + errors: + - code: invalid + key: name + message: message + payload: {} + value: name + schema: + properties: + errors: + $ref: '#/components/schemas/Errors' + type: object + description: "\u0421 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u043C \u0432\ + \u0441\u0435 \u0445\u043E\u0440\u043E\u0448\u043E, \u043D\u043E \u043F\ + \u0440\u0430\u0432\u0438\u043B\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\ + \u0430 \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0442\ + \ \u0435\u0433\u043E \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u0442\ + \u044C (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043F\u0440\ + \u0438 \u043F\u043E\u043F\u044B\u0442\u043A\u0435 \u0441\u043E\u0437\u0434\ + \u0430\u043D\u0438\u044F \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0430\ + \ \u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\ + \u0443\u044E\u0449\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C\ + \ \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0432 \u0431\u0430\ + \u0437\u0435)" + summary: "\u0421\u043F\u0438\u0441\u043E\u043A \u0431\u0435\u0441\u0435\u0434\ + \ \u0438 \u043A\u0430\u043D\u0430\u043B\u043E\u0432" + tags: + - chats and channels + post: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0441\u043E\ + \u0437\u0434\u0430\u043D\u0438\u044F \u043D\u043E\u0432\u043E\u0439 \u0431\ + \u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043D\u043E\u0432\u043E\ + \u0433\u043E \u043A\u0430\u043D\u0430\u043B\u0430.\n\u041F\u0440\u0438 \u0441\ + \u043E\u0437\u0434\u0430\u043D\u0438\u0438 \u0431\u0435\u0441\u0435\u0434\u044B\ + \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430 \u0432\u044B \u0430\ + \u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0441\ + \u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435\u0441\u044C \u0443\u0447\u0430\ + \u0441\u0442\u043D\u0438\u043A\u043E\u043C.\\\n" + operationId: createChat + requestBody: + content: + application/json: + schema: + properties: + chat: + $ref: '#/components/schemas/QueryChat' + type: object + required: true + responses: + '201': + content: + application/json: + schema: + properties: + data: + $ref: '#/components/schemas/Chat' + type: object + description: "\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0442\u0440\u0430\ + \u0431\u043E\u0442\u0430\u043B \u0443\u0441\u043F\u0435\u0448\u043D\u043E\ + , \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u044C \u0441\u043E\u0437\u0434\ + \u0430\u043D\u0430" + '400': + content: + application/json: + examples: + blank: + description: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ + \u043D\u043E\u0435 \u043F\u043E\u043B\u0435 (\u043D\u0435 \u043C\ + \u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\ + \u0441\u0442\u044B\u043C)" + value: + errors: + - code: blank + key: name + message: message + payload: {} + value: '' + invalid: + description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u0441\u043E\ + \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ + \ \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C (\u043F\u043E\ + \u044F\u0441\u043D\u0435\u043D\u0438\u044F \u0432\u044B \u043F\ + \u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u0432 \u043F\u043E\ + \u043B\u0435 message)" + value: + errors: + - code: invalid + key: name + message: message + payload: {} + value: 1234 + too_long: + description: "\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\ + \u0438\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\ + \u0438\u0435 (\u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\ + \u044F \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\ + \u0435 \u0432 \u043F\u043E\u043B\u0435 message)" + value: + errors: + - code: too_long + key: name + message: message + payload: {} + value: long_name + schema: + properties: + errors: + $ref: '#/components/schemas/Errors' + type: object + description: "\u041D\u0435\u043F\u0440\u0438\u0435\u043C\u043B\u0435\u043C\ + \u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 (\u0447\u0430\u0441\u0442\ + \u043E \u0438\u0437-\u0437\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\ + \u0432\u0438\u044F \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ + \u043D\u043E\u0433\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\ + \u0430)" + '404': + content: + application/json: + examples: + not_found: + description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438" + value: + errors: + - code: not_found + key: string + message: message + payload: {} + value: string + schema: + properties: + errors: + $ref: '#/components/schemas/Errors' + type: object + description: "\u0417\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\ + \u043C\u044B\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043D\u0435 \u0441\ + \u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442" + '422': + content: + application/json: + examples: + invalid: + description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\ + \u0440\u043C\u0430\u0442 (\u0438\u0434\u0435\u043D\u0442\u0438\ + \u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044F\ + \ \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0435\ + \ \u0432 \u043F\u043E\u043B\u0435 payload)" + value: + errors: + - code: invalid + key: name + message: message + payload: {} + value: name + schema: + properties: + errors: + $ref: '#/components/schemas/Errors' + type: object + description: "\u0421 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u043C \u0432\ + \u0441\u0435 \u0445\u043E\u0440\u043E\u0448\u043E, \u043D\u043E \u043F\ + \u0440\u0430\u0432\u0438\u043B\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\ + \u0430 \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0442\ + \ \u0435\u0433\u043E \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u0442\ + \u044C (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043F\u0440\ + \u0438 \u043F\u043E\u043F\u044B\u0442\u043A\u0435 \u0441\u043E\u0437\u0434\ + \u0430\u043D\u0438\u044F \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0430\ + \ \u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\ + \u0443\u044E\u0449\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C\ + \ \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0432 \u0431\u0430\ + \u0437\u0435)" + summary: "\u041D\u043E\u0432\u0430\u044F \u0431\u0435\u0441\u0435\u0434\u0430\ + \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B" + tags: + - chats and channels + /chats/{id}: + get: + description: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0438\u043D\ + \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0431\u0435\u0441\ + \u0435\u0434\u0435 \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0435\ + .\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F\ + \ \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\ + \u0430\u043B\u0430 \u0432\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\ + \u0434\u0438\u043C\u043E \u0437\u043D\u0430\u0442\u044C \u0435\u0451 id \u0438\ + \ \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL\ + \ \u0437\u0430\u043F\u0440\u043E\u0441\u0430.\n" + operationId: getChat + parameters: + - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438\ + \ \u043A\u0430\u043D\u0430\u043B\u0430" + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + properties: + data: + $ref: '#/components/schemas/Chat' + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + '404': + content: + application/json: + examples: + not_found: + description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438" + value: + errors: + - code: not_found + key: string + message: message + payload: {} + value: string + schema: + properties: + errors: + $ref: '#/components/schemas/Errors' + type: object + description: "\u0417\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\ + \u043C\u044B\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043D\u0435 \u0441\ + \u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442" + summary: "\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ + \ \u0431\u0435\u0441\u0435\u0434\u0435 \u0438\u043B\u0438 \u043A\u0430\u043D\ + \u0430\u043B\u0435" + tags: + - chats and channels + /chats/{id}/group_tags: + post: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0434\u043E\ + \u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0442\u0435\u0433\u043E\u0432\ + \ \u0432 \u0441\u043E\u0441\u0442\u0430\u0432 \u0443\u0447\u0430\u0441\u0442\ + \u043D\u0438\u043A\u043E\u0432 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\ + \u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430.\n" + operationId: postTagsToChats + parameters: + - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\u0430\u043D\ + \u0430\u043B\u0430" + in: path + name: id + required: true + schema: + example: 533 + format: int64 + type: integer + requestBody: + content: + application/json: + schema: + properties: + group_tag_ids: + example: + - 86 + - 18 + items: + format: int64 + type: integer + minItems: 1 + type: array + required: + - group_tag_ids + type: object + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ + \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u0442\ + \u0435\u0433\u043E\u0432, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\ + \u0442\u0430\u043D\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\ + \u043A\u0430\u043C\u0438" + responses: + '201': + description: "\u0422\u0435\u0433(\u0438) \u0434\u043E\u0431\u0430\u0432\u043B\ + \u0435\u043D(\u044B)" + '400': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ErrorsCode' + type: array + description: BadRequest + summary: "\u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0442\ + \u0435\u0433\u043E\u0432 \u0432 \u0441\u043E\u0441\u0442\u0430\u0432 \u0443\ + \u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u0432 \u0431\u0435\u0441\u0435\ + \u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430" + tags: + - talk and channel participants + /chats/{id}/leave: + delete: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0441\u0430\ + \u043C\u043E\u0441\u0442\u043E\u044F\u0442\u0435\u043B\u044C\u043D\u043E\u0433\ + \u043E \u0432\u044B\u0445\u043E\u0434\u0430 \u0438\u0437 \u0431\u0435\u0441\ + \u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430\ + ." + operationId: leaveChat + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\ + \u043D\u0430\u043B\u0430." + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0442\u043F\ + \u0438\u0441\u0430\u043D. \u0422\u0435\u043B\u043E \u043E\u0442\u0432\u0435\ + \u0442\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\ + \u0442" + '400': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ErrorsCode' + type: array + description: "\u041D\u0435\u043B\u044C\u0437\u044F \u043F\u043E\u043A\u0438\ + \u043D\u0443\u0442\u044C \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\ + \u044C\u043D\u044B\u0439 \u0447\u0430\u0442" + '404': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ErrorsCode' + type: array + description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043D\ + \u0430\u0439\u0442\u0438" + summary: "\u0412\u044B\u0445\u043E\u0434 \u0438\u0437 \u0431\u0435\u0441\u0435\ + \u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430" + tags: + - talk and channel participants + /chats/{id}/members: + post: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0434\u043E\ + \u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\ + \u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u0441\u043E\u0441\ + \u0442\u0430\u0432 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u0432\ + \ \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\ + \u0430\u043B\u0430.\n" + operationId: postMembersToChats + parameters: + - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\u0430\u043D\ + \u0430\u043B\u0430" + in: path + name: id + required: true + schema: + example: 533 + format: int64 + type: integer + requestBody: + content: + application/json: + schema: + properties: + member_ids: + example: + - 186 + - 187 + items: + format: int64 + type: integer + minItems: 1 + type: array + silent: + type: boolean + required: + - member_ids + type: object + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ + \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u043F\ + \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439\ + , \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\u0442\u0430\u043D\u0443\ + \u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u0430\u043C\u0438" + responses: + '201': + description: "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\ + \u043B\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B" + '400': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ErrorsCode' + type: array + description: BadRequest + summary: "\u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\ + \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432\ + \ \u0441\u043E\u0441\u0442\u0430\u0432 \u0443\u0447\u0430\u0441\u0442\u043D\ + \u0438\u043A\u043E\u0432" + tags: + - talk and channel participants + /custom_properties: + get: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u043A\u0442\u0443\u0430\u043B\ + \u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0430 \u0434\ + \u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445\ + \ \u043F\u043E\u043B\u0435\u0439 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\ + \u043A\u043E\u0432 \u0438 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\ + \u043D\u0438\u0439 \u0432 \u0432\u0430\u0448\u0435\u0439 \u043A\u043E\u043C\ + \u043F\u0430\u043D\u0438\u0438.\n" + operationId: getCommonMethods + parameters: + - description: "\u0422\u0438\u043F \u0441\u0443\u0449\u043D\u043E\u0441\u0442\ + \u0438 - \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A (User) \u0438\u043B\ + \u0438 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u0435\ + \ (Task)." + in: query + name: entity_type + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + $ref: '#/components/schemas/QueryCommonMethods' + type: array + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + '400': + content: + application/json: + examples: + BLANK: + description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ + \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ + \u0442\u044B\u043C" + summary: blank + value: + detail: BLANK + INCLUSION: + description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u043F\u0440\u0435\u0434\u0443\u0441\u043C\u043E\ + \u0442\u0440\u0435\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\ + \u0435\u043D\u0438\u0435" + summary: inclusion + value: + detail: INCLUSION + schema: + $ref: '#/components/schemas/BadRequest' + description: BadRequest + summary: "\u0421\u043F\u0438\u0441\u043E\u043A \u0434\u043E\u043F\u043E\u043B\ + \u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u043F\u043E\u043B\u0435\ + \u0439" + tags: + - common methods + /direct_url: + post: + description: "\u041E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u0442 \u0437\ + \u0430\u043F\u0440\u043E\u0441 \u0434\u043B\u044F \u043F\u043E\u043B\u0443\ + \u0447\u0435\u043D\u0438\u044F URL \u0434\u043B\u044F \u0431\u0435\u0437\u043E\ + \u043F\u0430\u0441\u043D\u043E\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\ + \u0438 \u0444\u0430\u0439\u043B\u0430." + operationId: getDirectUrl + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + required: true + responses: + '204': + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441." + summary: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 URL \u0434\u043B\ + \u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438" + tags: + - common methods + /group_tags: + get: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u043A\u0442\u0443\u0430\u043B\ + \u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0430 \u0442\ + \u0435\u0433\u043E\u0432 \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\ + \u043E\u0432.\n" + operationId: getTags + parameters: + - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ + \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ + \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ + \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\ + \u0438\u043C\u0443\u043C 50)" + in: query + name: per + required: false + schema: + default: 50 + maximum: 50 + type: integer + - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ + \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ + \u0430\u043D\u0438\u044E 1)" + in: query + name: page + required: false + schema: + default: 1 + type: integer + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + $ref: '#/components/schemas/Tag' + type: array + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + '400': + content: + application/json: + examples: + exclusion: + summary: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\ + \u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\ + \ \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\ + \u044B\u0445 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439\ + \ \u0437\u0430 \u043E\u0434\u0438\u043D \u0437\u0430\u043F\u0440\ + \u043E\u0441" + value: + errors: + - code: exclusion + key: per + message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ + \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" + value: '51' + schema: + properties: + errors: + description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ + \u0438\u0431\u043E\u043A \u0432 \u0437\u0430\u043F\u0440\u043E\ + \u0441\u0435." + items: + properties: + code: + description: "\u0412\u043D\u0443\u0442\u0440\u0435\u043D\ + \u043D\u0438\u0439 \u043A\u043E\u0434 \u043E\u0448\u0438\ + \u0431\u043A\u0438." + type: string + key: + description: "\u041A\u043B\u044E\u0447 \u043F\u0430\u0440\ + \u0430\u043C\u0435\u0442\u0440\u0430, \u0432 \u043A\u043E\ + \u0442\u043E\u0440\u043E\u043C \u043F\u0440\u043E\u0438\ + \u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\ + \u043A\u0430." + type: string + message: + description: "\u0422\u0435\u043A\u0441\u0442\u043E\u0432\ + \u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\ + \u0435 \u043E\u0448\u0438\u0431\u043A\u0438." + type: string + payload: + description: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\ + \u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0438\u043D\ + \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ + \u0431 \u043E\u0448\u0438\u0431\u043A\u0435." + type: object + value: + description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ + \u0435 \u043A\u043B\u044E\u0447\u0430, \u0432\u044B\u0437\ + \u0432\u0430\u0432\u0448\u0435\u0435 \u043E\u0448\u0438\ + \u0431\u043A\u0443." + type: string + type: object + type: array + type: object + description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\ + \u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\ + ." + summary: "\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u0435\u0433\u043E\u0432\ + \ \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432" + tags: + - tags + /group_tags/{id}: + get: + description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\ + \u043F\u0440\u043E\u0441\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\ + \u0443\u044E\u0442\n" + operationId: getTag + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0442\u0435\u0433\u0430" + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + properties: + data: + $ref: '#/components/schemas/Tag' + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + '404': + content: + application/json: + examples: + not_found: + summary: "\u0422\u0435\u0433 \u043D\u0435 \u043D\u0430\u0439\u0434\ + \u0435\u043D." + value: + errors: + - code: not_found + key: id + message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438 \u0442\u0435\u0433" + value: '100500' + schema: + properties: + errors: + description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ + \u0438\u0431\u043E\u043A." + items: + properties: + code: + type: string + key: + type: string + message: + type: string + payload: + type: object + value: + type: string + type: object + type: array + type: object + description: "\u0422\u0435\u0433 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\ + \u043D." + summary: "\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ + \ \u0442\u0435\u0433\u0435" + tags: + - tags + /group_tags/{id}/users: + get: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u043A\u0442\u0443\u0430\u043B\ + \u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0430 \u0441\ + \u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432 \u0442\u0435\u0433\ + \u0430.\n" + operationId: getTagsEmployees + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0441\u043E\u0442\u0440\u0443\u0434\u043A\u0438\u043A\u0430" + in: path + name: id + required: true + schema: + type: integer + - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ + \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ + \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ + \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\ + \u0438\u043C\u0443\u043C" + in: query + name: per + required: false + schema: + default: 25 + maximum: 50 + type: integer + - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ + \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ + \u0430\u043D\u0438\u044E 1)" + in: query + name: page + required: false + schema: + default: 1 + type: integer + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + $ref: '#/components/schemas/BaseEmployee' + type: array + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442 \u043D\ + \u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0437\ + \u043D\u0430\u0447\u0435\u043D\u0438\u0435" + summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0430\u043A\ + \u0442\u0443\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\ + \u043A\u0430 \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432\ + \ \u0442\u0435\u0433\u0430" + tags: + - tags + /messages: + get: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u043F\u0438\u0441\u043A\u0430\ + \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439 \u0431\u0435\u0441\ + \u0435\u0434, \u043A\u0430\u043D\u0430\u043B\u043E\u0432, \u0442\u0440\u0435\ + \u0434\u043E\u0432 \u0438 \u043B\u0438\u0447\u043D\u044B\u0445 \u0441\u043E\ + \u043E\u0431\u0449\u0435\u043D\u0438\u0439.\n\n\u0414\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u0439 \u0432\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\ + \u0434\u0438\u043C\u043E \u0437\u043D\u0430\u0442\u044C chat_id \u0442\u0440\ + \u0435\u0431\u0443\u0435\u043C\u043E\u0439 \u0431\u0435\u0441\u0435\u0434\u044B\ + , \u043A\u0430\u043D\u0430\u043B\u0430,\n\u0442\u0440\u0435\u0434\u0430 \u0438\ + \u043B\u0438 \u0434\u0438\u0430\u043B\u043E\u0433\u0430, \u0438 \u0443\u043A\ + \u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\ + \u0440\u043E\u0441\u0430. \u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ + \u044F \u0431\u0443\u0434\u0443\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\ + \u0449\u0435\u043D\u044B\n\u0432 \u043F\u043E\u0440\u044F\u0434\u043A\u0435\ + \ \u0443\u0431\u044B\u0432\u0430\u043D\u0438\u044F \u0434\u0430\u0442\u044B\ + \ \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 (\u0442\u043E \u0435\u0441\ + \u0442\u044C, \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0431\u0443\u0434\ + \u0443\u0442 \u0438\u0434\u0442\u0438 \u043F\u043E\u0441\u043B\u0435\u0434\ + \u043D\u0438\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + \ \u0447\u0430\u0442\u0430).\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\ + \u0435\u043D\u0438\u044F \u0431\u043E\u043B\u0435\u0435 \u0440\u0430\u043D\ + \u043D\u0438\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439\ + \ \u0447\u0430\u0442\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\ + \ \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B per \u0438 page.\n" + operationId: getListMessage + parameters: + - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ + \u0442\u043E\u0440 \u0447\u0430\u0442\u0430 (\u0431\u0435\u0441\u0435\u0434\ + \u0430, \u043A\u0430\u043D\u0430\u043B, \u0434\u0438\u0430\u043B\u043E\u0433\ + \ \u0438\u043B\u0438 \u0447\u0430\u0442 \u0442\u0440\u0435\u0434\u0430)" + in: query + name: chat_id + required: true + schema: + title: chat_id + type: integer + - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ + \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ + \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441\n(\u043F\u043E \u0443\ + \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 25, \u043C\u0430\u043A\u0441\ + \u0438\u043C\u0443\u043C 50)\n" + in: query + name: per + schema: + default: 25 + maximum: 50 + title: per + type: integer + - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ + \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ + \u0430\u043D\u0438\u044E 1)" + in: query + name: page + schema: + default: 1 + title: page + type: integer + responses: + '200': + content: + application/json: + example: + data: + - buttons: [] + chat_id: 198 + content: "\u042D\u0442\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u0435 \u0442\u043E\u0436\u0435 \u043F\u043E\u043F\ + \u0430\u0434\u0451\u0442 \u0432 \u044D\u043A\u0441\u043F\u043E\ + \u0440\u0442" + created_at: 2023-09-18 13:43:32+00:00 + entity_id: 198 + entity_type: discussion + files: [] + forwarding: null + id: 1194277 + parent_message_id: null + thread: + chat_id: 44997 + id: 2633 + user_id: 12 + - buttons: [] + chat_id: 198 + content: "**Andrew** \u0434\u043E\u0431\u0430\u0432\u0438\u043B\ + \ **Export bot** \u0432 \u0431\u0435\u0441\u0435\u0434\u0443" + created_at: 2023-09-18 13:43:27+00:00 + entity_id: 198 + entity_type: discussion + files: [] + forwarding: null + id: 1194276 + parent_message_id: null + thread: null + user_id: 12 + - buttons: [] + chat_id: 198 + content: "**Andrew** \u0441\u043E\u0437\u0434\u0430\u043B \u0431\ + \u0435\u0441\u0435\u0434\u0443" + created_at: 2023-09-18 13:43:19+00:00 + entity_id: 198 + entity_type: discussion + files: [] + forwarding: null + id: 1194275 + parent_message_id: null + thread: null + user_id: 12 + schema: + properties: + data: + items: + $ref: '#/components/schemas/Message' + type: array + type: object + description: Successful + '400': + content: + application/json: + examples: + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - code: exclusion + key: chat_id + message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ + \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" + value: chat + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - code: blank + key: chat_id + message: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ + \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ + \u0442\u044B\u043C" + value: null + schema: + $ref: '#/components/schemas/BadRequest' + description: Bad Request + '404': + content: + application/json: + example: + errors: + - code: not_found + key: chat_id + message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438" + value: 1 + schema: + $ref: '#/components/schemas/NotFound' + description: Not Found + summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0441\u043F\ + \u0438\u0441\u043A\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439\ + \ \u0447\u0430\u0442\u0430" + tags: + - messages + post: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043E\u0442\ + \u043F\u0440\u0430\u0432\u043A\u0438 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ + \u0438\u044F \u0432 \u0431\u0435\u0441\u0435\u0434\u0443 \u0438\u043B\u0438\ + \ \u043A\u0430\u043D\u0430\u043B,\n\u043B\u0438\u0447\u043D\u043E\u0433\u043E\ + \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u043E\u043B\ + \u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0438\u043B\u0438\ + \ \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F \u0432\ + \ \u0442\u0440\u0435\u0434.\n\n\u041F\u0440\u0438 \u0438\u0441\u043F\u043E\ + \u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0438 entity_type: \"discussion\"\ + \ (\u0438\u043B\u0438 \u043F\u0440\u043E\u0441\u0442\u043E \u0431\u0435\u0437\ + \ \u0443\u043A\u0430\u0437\u0430\u043D\u0438\u044F entity_type)\n\u0434\u043E\ + \u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\u044F \u043E\u0442\u043F\u0440\ + \u0430\u0432\u043A\u0430 \u043B\u044E\u0431\u043E\u0433\u043E chat_id \u0432\ + \ \u043F\u043E\u043B\u0435 entity_id.\n\u0422\u043E \u0435\u0441\u0442\u044C\ + , \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\ + \u043D\u043E \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0437\ + \u043D\u0430\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0434\u0435\ + \u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0447\u0430\u0442\ + \u0430.\n\u041F\u0440\u0438 \u044D\u0442\u043E\u043C, \u0432\u044B \u0438\u043C\ + \u0435\u0435\u0442\u0435 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\ + \u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0441\ + \u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0432 \u0442\u0440\u0435\ + \u0434 \u043F\u043E \u0435\u0433\u043E \u0438\u0434\u0435\u043D\u0442\u0438\ + \u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443\n\u0438\u043B\u0438 \u043B\ + \u0438\u0447\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ + \u0435 \u043F\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ + \u0430\u0442\u043E\u0440\u0443 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\ + \u0442\u0435\u043B\u044F.\n\n\u0414\u043B\u044F \u043E\u0442\u043F\u0440\u0430\ + \u0432\u043A\u0438 \u043B\u0438\u0447\u043D\u043E\u0433\u043E \u0441\u043E\ + \u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\ + \u0432\u0430\u0442\u0435\u043B\u044E \u0441\u043E\u0437\u0434\u0430\u0432\u0430\ + \u0442\u044C \u0447\u0430\u0442 \u043D\u0435 \u0442\u0440\u0435\u0431\u0443\ + \u0435\u0442\u0441\u044F. \n\u0414\u043E\u0441\u0442\u0430\u0442\u043E\u0447\ + \u043D\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C entity_type: \"user\"\ + \ \u0438 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\ + \u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ + \u044F. \n\u0427\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043E\u0437\ + \u0434\u0430\u043D \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\ + \u0441\u043A\u0438, \u0435\u0441\u043B\u0438 \u043C\u0435\u0436\u0434\u0443\ + \ \u0432\u0430\u043C\u0438 \u0435\u0449\u0451 \u043D\u0435 \u0431\u044B\u043B\ + \u043E \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438.\n\u041C\u0435\ + \u0436\u0434\u0443 \u0434\u0432\u0443\u043C\u044F \u043F\u043E\u043B\u044C\ + \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438 \u043C\u043E\u0436\ + \u0435\u0442 \u0431\u044B\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E\ + \ \u043E\u0434\u0438\u043D \u043B\u0438\u0447\u043D\u044B\u0439 \u0447\u0430\ + \u0442.\n" + operationId: createMessage + requestBody: + content: + application/json: + example: + message: + content: "\u0412\u0447\u0435\u0440\u0430 \u043C\u044B \u043F\u0440\ + \u043E\u0434\u0430\u043B\u0438 756 \u0444\u0443\u0442\u0431\u043E\ + \u043B\u043E\u043A (\u0447\u0442\u043E \u043D\u0430 10% \u0431\u043E\ + \u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432 \u043F\u0440\ + \u043E\u0448\u043B\u043E\u0435 \u0432\u043E\u0441\u043A\u0440\u0435\ + \u0441\u0435\u043D\u044C\u0435)" + entity_id: 198 + entity_type: discussion + schema: + properties: + message: + $ref: '#/components/schemas/CreateMessage' + type: object + required: true + responses: + '201': + content: + application/json: + example: + data: + buttons: [] + chat_id: 198 + content: "\u0412\u0447\u0435\u0440\u0430 \u043C\u044B \u043F\u0440\ + \u043E\u0434\u0430\u043B\u0438 756 \u0444\u0443\u0442\u0431\u043E\ + \u043B\u043E\u043A (\u0447\u0442\u043E \u043D\u0430 10% \u0431\ + \u043E\u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432 \u043F\ + \u0440\u043E\u0448\u043B\u043E\u0435 \u0432\u043E\u0441\u043A\u0440\ + \u0435\u0441\u0435\u043D\u044C\u0435)" + created_at: 2020-06-08 09:32:57+00:00 + entity_id: 198 + entity_type: discussion + files: [] + forwarding: null + id: 194275 + parent_message_id: null + thread: null + user_id: 12 + schema: + properties: + data: + $ref: '#/components/schemas/Message' + type: object + description: Successful + '400': + content: + application/json: + examples: + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - code: exclusion + key: entity_type + message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ + \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" + value: chat + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - code: blank + key: content + message: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ + \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ + \u0442\u044B\u043C" + value: null + schema: + $ref: '#/components/schemas/BadRequest' + description: Bad Request + '404': + content: + application/json: + example: + errors: + - code: not_found + key: entyti_id + message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438" + value: 1 + schema: + $ref: '#/components/schemas/Errors' + description: Not Found + summary: "\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u043E\u0432\ + \u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F" + tags: + - messages + /messages/{id}: + get: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0438\u043D\u0444\u043E\u0440\u043C\ + \u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ + \u0438\u0438.\n\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\ + \u0438\u044F \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0432\ + \u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\ + \ \u0437\u043D\u0430\u0442\u044C \u0435\u0433\u043E id \u0438 \u0443\u043A\ + \u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\ + \u0440\u043E\u0441\u0430.\n" + operationId: getMessage + parameters: + - in: path + name: id + required: true + schema: + title: id + type: integer + responses: + '200': + content: + application/json: + example: + data: + buttons: [] + chat_id: 198 + content: "\u0412\u0447\u0435\u0440\u0430 \u043C\u044B \u043F\u0440\ + \u043E\u0434\u0430\u043B\u0438 756 \u0444\u0443\u0442\u0431\u043E\ + \u043B\u043E\u043A (\u0447\u0442\u043E \u043D\u0430 10% \u0431\ + \u043E\u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432 \u043F\ + \u0440\u043E\u0448\u043B\u043E\u0435 \u0432\u043E\u0441\u043A\u0440\ + \u0435\u0441\u0435\u043D\u044C\u0435)" + created_at: 2020-06-08 09:32:57+00:00 + entity_id: 198 + entity_type: discussion + files: + - file_type: file + id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + url: "https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934-\n\ + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max-\n\ + \ age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC\n\ + \ -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_\n\ + \ request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=\n\ + \ host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8\n" + forwarding: null + id: 194275 + parent_message_id: 194274 + thread: + chat_id: 1949863 + id: 29873 + user_id: 12 + schema: + properties: + data: + $ref: '#/components/schemas/Message' + type: object + description: Successfull + '404': + content: + application/json: + example: + errors: + - code: not_found + key: id + message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438" + value: 0 + schema: + $ref: '#/components/schemas/NotFound' + description: Not Found + summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0438\u043D\ + \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u043E\ + \u0431\u0449\u0435\u043D\u0438\u0438" + tags: + - messages + put: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0440\u0435\ + \u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0441\ + \u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0438\u043B\u0438 \u043A\ + \u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F." + operationId: editMessage + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\ + \u043D\u0430\u043B\u0430." + in: path + name: id + required: true + schema: + type: integer + requestBody: + content: + application/json: + schema: + properties: + message: + $ref: '#/components/schemas/EditMessages' + type: object + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ + \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u0442\ + \u0435\u0433\u043E\u0432, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\ + \u0442\u0430\u043D\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\ + \u043A\u0430\u043C\u0438" + responses: + '200': + content: + application/json: + schema: + properties: + data: + description: "\u0421\u043E\u0437\u0434\u0430\u043D\u043D\u043E\ + \u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435" + items: + $ref: '#/components/schemas/Message' + type: array + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0442\u0440\ + \u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043E" + '400': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ErrorsCode' + type: array + description: "\u041D\u0435\u043B\u044C\u0437\u044F \u043F\u043E\u043A\u0438\ + \u043D\u0443\u0442\u044C \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\ + \u044C\u043D\u044B\u0439 \u0447\u0430\u0442" + '404': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ErrorsCode' + type: array + description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043D\ + \u0430\u0439\u0442\u0438" + summary: "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\ + \u043D\u0438\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F" + tags: + - message + /messages/{id}/reactions: + delete: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0443\u0434\ + \u0430\u043B\u0435\u043D\u0438\u044F \u0440\u0435\u0430\u043A\u0446\u0438\u0438\ + \ \u043D\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435. \u0423\ + \u0434\u0430\u043B\u0438\u0442\u044C \u043C\u043E\u0436\u043D\u043E \u0442\ + \u043E\u043B\u044C\u043A\u043E \u0442\u0435 \u0440\u0435\u0430\u043A\u0446\ + \u0438\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u044B\u043B\ + \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u044B \u0430\ + \u0432\u0442\u043E\u0440\u0438\u0437\u043E\u0432\u0430\u043D\u043D\u044B\u043C\ + \ \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\ + \u043C.\n" + operationId: deleteMessageReactions + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F." + in: path + name: id + required: true + schema: + type: integer + - description: "Emoji, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043D\u0443\ + \u0436\u043D\u043E \u0443\u0434\u0430\u043B\u0438\u0442\u044C." + in: query + name: code + required: true + schema: + type: string + responses: + '204': + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E\u0435 \u0432\u044B\ + \u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u0437\u0430\u043F\u0440\ + \u043E\u0441\u0430, \u0442\u0435\u043B\u043E \u043E\u0442\u0432\u0435\u0442\ + \u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ + ." + '400': + content: + application/json: + examples: + blank_field: + summary: "\u041F\u043E\u043B\u0435 code \u043F\u0443\u0441\u0442\ + \u043E\u0435" + value: + errors: + - code: blank + key: code + message: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ + \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ + \u0442\u044B\u043C" + value: '' + exclusion: + summary: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\ + \u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\ + \ \u044D\u043C\u043E\u0434\u0437\u0438" + value: + errors: + - code: exclusion + key: code + message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ + \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ + \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" + value: invalid_emoji + schema: + properties: + errors: + description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ + \u0438\u0431\u043E\u043A \u0432 \u0437\u0430\u043F\u0440\u043E\ + \u0441\u0435." + items: + properties: + code: + description: "\u0412\u043D\u0443\u0442\u0440\u0435\u043D\ + \u043D\u0438\u0439 \u043A\u043E\u0434 \u043E\u0448\u0438\ + \u0431\u043A\u0438." + type: string + key: + description: "\u041A\u043B\u044E\u0447 \u043F\u0430\u0440\ + \u0430\u043C\u0435\u0442\u0440\u0430, \u0432 \u043A\u043E\ + \u0442\u043E\u0440\u043E\u043C \u043F\u0440\u043E\u0438\ + \u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\ + \u043A\u0430." + type: string + message: + description: "\u0422\u0435\u043A\u0441\u0442\u043E\u0432\ + \u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\ + \u0435 \u043E\u0448\u0438\u0431\u043A\u0438." + type: string + payload: + description: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\ + \u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0438\u043D\ + \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ + \u0431 \u043E\u0448\u0438\u0431\u043A\u0435." + type: object + value: + description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ + \u0435 \u043A\u043B\u044E\u0447\u0430, \u0432\u044B\u0437\ + \u0432\u0430\u0432\u0448\u0435\u0435 \u043E\u0448\u0438\ + \u0431\u043A\u0443." + type: string + type: object + type: array + type: object + description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\ + \u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\ + ." + '404': + content: + application/json: + examples: + not_found: + summary: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + \ \u0438\u043B\u0438 \u0440\u0435\u0430\u043A\u0446\u0438\u044F\ + \ \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B" + value: + errors: + - code: not_found + key: reaction + message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ + \ \u043D\u0430\u0439\u0442\u0438 \u0440\u0435\u0430\u043A\u0446\ + \u0438\u044E" + value: "\U0001F60A" + schema: + properties: + errors: + description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ + \u0438\u0431\u043E\u043A." + items: + properties: + code: + type: string + key: + type: string + message: + type: string + payload: + type: object + value: + type: string + type: object + type: array + type: object + description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0438\ + \u043B\u0438 \u0440\u0435\u0430\u043A\u0446\u0438\u044F \u043D\u0435 \u043D\ + \u0430\u0439\u0434\u0435\u043D\u044B." + summary: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0440\u0435\u0430\ + \u043A\u0446\u0438\u0438" + tags: + - reactions to messages + get: + description: "\u042D\u0442\u043E\u0442 \u043C\u0435\u0442\u043E\u0434 \u043F\ + \u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u043F\u043E\u043B\u0443\u0447\ + \u0438\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u0432\u0441\u0435\ + \u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439, \u043E\u0441\u0442\u0430\ + \u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\ + \u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438 \u043D\u0430 \u0443\u043A\ + \u0430\u0437\u0430\u043D\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\ + \u043D\u0438\u0435.\n" + operationId: getMessageReactions + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F, \u0441\u043F\ + \u0438\u0441\u043E\u043A \u0440\u0435\u0430\u043A\u0446\u0438\u0439 \u043D\ + \u0430 \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043D\u0443\u0436\u043D\ + \u043E \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C." + in: path + name: id + required: true + schema: + type: integer + requestBody: + content: + application/json: + schema: + properties: + page: + default: 1 + description: "\u041D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u0430\ + \u043D\u0438\u0446\u044B \u0432\u044B\u0431\u043E\u0440\u043A\u0438\ + \ (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\ + \u044E 1)." + type: integer + per: + default: 50 + description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\ + \u043E \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\ + \u044B\u0445 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439\ + \ \u0437\u0430 \u043E\u0434\u0438\u043D \u0437\u0430\u043F\u0440\ + \u043E\u0441 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\ + \u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\u0438\u043C\u0443\ + \u043C 50)." + maximum: 50 + type: integer + type: object + required: false + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + $ref: '#/components/schemas/Reaction' + type: array + type: object + description: "\u0421\u043F\u0438\u0441\u043E\u043A \u0440\u0435\u0430\u043A\ + \u0446\u0438\u0439 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D." + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + description: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441." + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\ + \u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E." + summary: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0430\u043A\ + \u0442\u0443\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\ + \u043A\u0430 \u0440\u0435\u0430\u043A\u0446\u0438\u0439." + tags: + - reactions to messages + post: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0434\u043E\ + \u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0440\u0435\u0430\u043A\u0446\ + \u0438\u0438 \u043D\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ + \u0435. **\u041B\u0438\u043C\u0438\u0442\u044B \u0440\u0435\u0430\u043A\u0446\ + \u0438\u0439:** - \u041A\u0430\u0436\u0434\u044B\u0439 \u043F\u043E\u043B\u044C\ + \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043C\u043E\u0436\u0435\u0442\ + \ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043D\u0435\ + \ \u0431\u043E\u043B\u0435\u0435 20 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\ + \u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439 \u043D\u0430\ + \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435. - \u0421\u043E\u043E\ + \u0431\u0449\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\u0435\u0442 \u0438\ + \u043C\u0435\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 30 \u0443\ + \u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0445 \u0440\u0435\u0430\u043A\ + \u0446\u0438\u0439. - \u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + \ \u043C\u043E\u0436\u0435\u0442 \u0438\u043C\u0435\u0442\u044C \u043D\u0435\ + \ \u0431\u043E\u043B\u0435\u0435 1000 \u0440\u0435\u0430\u043A\u0446\u0438\ + \u0439.\n" + operationId: postMessageReactions + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F." + in: path + name: id + required: true + schema: + type: integer + requestBody: + content: + application/json: + schema: + properties: + code: + description: "Emoji \u0432 \u0441\u0442\u0440\u043E\u043A\u043E\u0432\ + \u043E\u043C \u0444\u043E\u0440\u043C\u0430\u0442\u0435 \u0434\ + \u043B\u044F \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\ + \u044F \u0440\u0435\u0430\u043A\u0446\u0438\u0438." + type: string + required: + - code + type: object + required: true + responses: + '204': + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E\u0435 \u0432\u044B\ + \u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u0437\u0430\u043F\u0440\ + \u043E\u0441\u0430, \u0442\u0435\u043B\u043E \u043E\u0442\u0432\u0435\u0442\ + \u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ + ." + '400': + content: + application/json: + examples: + blank_field: + summary: "\u041F\u043E\u043B\u0435 code \u043F\u0443\u0441\u0442\ + \u043E\u0435" + value: + error: blank + exclusion: + summary: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\ + \u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\ + \ \u044D\u043C\u043E\u0434\u0437\u0438" + value: + error: exclusion + schema: + properties: + error: + description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ + \ \u043E\u0448\u0438\u0431\u043A\u0438." + type: string + type: object + description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\ + \u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\ + ." + '403': + content: + application/json: + examples: + general_limit: + summary: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043E\ + \u0431\u0449\u0438\u0439 \u043B\u0438\u043C\u0438\u0442 \u0440\ + \u0435\u0430\u043A\u0446\u0438\u0439 \u043D\u0430 \u0441\u043E\ + \u043E\u0431\u0449\u0435\u043D\u0438\u0435" + value: + error: general_limit + message: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + \ \u043C\u043E\u0436\u0435\u0442 \u0441\u043E\u0434\u0435\u0440\ + \u0436\u0430\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\ + \u0435 1000 \u0440\u0435\u0430\u043A\u0446\u0438\u0439." + unique_limit: + summary: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043B\ + \u0438\u043C\u0438\u0442 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\ + \u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439\ + \ \u043D\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ + \u0435" + value: + error: unique_limit + message: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + \ \u043C\u043E\u0436\u0435\u0442 \u0441\u043E\u0434\u0435\u0440\ + \u0436\u0430\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\ + \u0435 30 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\ + \u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439." + user_limit: + summary: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043B\ + \u0438\u043C\u0438\u0442 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\ + \u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439\ + \ \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\ + \u043B\u044F" + value: + error: user_limit + message: "\u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0434\ + \u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0431\ + \u043E\u043B\u0435\u0435 20 \u0443\u043D\u0438\u043A\u0430\u043B\ + \u044C\u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\ + \u0439." + schema: + properties: + error: + description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ + \ \u043E\u0448\u0438\u0431\u043A\u0438." + type: string + type: object + description: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D\u0438\u0435\ + \ \u043B\u0438\u043C\u0438\u0442\u043E\u0432 \u043F\u043E \u0440\u0435\ + \u0430\u043A\u0446\u0438\u044F\u043C." + '404': + content: + application/json: + examples: + not_found: + summary: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ + \ \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\ + \u0435\u0442" + value: + error: not_found + schema: + properties: + error: + description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ + \u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E\ + ." + type: string + type: object + description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\ + \u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E." + summary: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\ + \u0435\u0430\u043A\u0446\u0438\u0438" + tags: + - reactions to messages + /messages/{id}/thread: + post: + description: "\u042D\u0442\u043E\u0442 \u043C\u0435\u0442\u043E\u0434 \u043F\ + \u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0441\u043E\u0437\u0434\u0430\ + \u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u0442\u0440\u0435\u0434 \u043A\ + \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044E. \u0415\u0441\u043B\ + \u0438 \u0443 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0443\ + \u0436\u0435 \u0431\u044B\u043B \u0441\u043E\u0437\u0434\u0430\u043D \u0442\ + \u0440\u0435\u0434, \u0442\u043E \u0432 \u043E\u0442\u0432\u0435\u0442\u0435\ + \ \u0432\u0435\u0440\u043D\u0451\u0442\u0441\u044F \u0438\u043D\u0444\u043E\ + \u0440\u043C\u0430\u0446\u0438\u044F \u043E\u0431 \u0443\u0436\u0435 \u0441\ + \u043E\u0437\u0434\u0430\u043D\u043D\u043E\u043C \u0440\u0430\u043D\u0435\u0435\ + \ \u0442\u0440\u0435\u0434\u0435.\n" + operationId: createThread + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F, \u043A \u043A\ + \u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u0441\u043E\u0437\u0434\u0430\ + \u0435\u0442\u0441\u044F \u0442\u0440\u0435\u0434." + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + properties: + data: + properties: + chat_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ + \u043A\u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430\ + \ \u0442\u0440\u0435\u0434\u0430." + type: integer + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ + \u043A\u0430\u0442\u043E\u0440 \u0441\u043E\u0437\u0434\u0430\ + \u043D\u043D\u043E\u0433\u043E \u0442\u0440\u0435\u0434\u0430\ + ." + type: integer + message_chat_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ + \u043A\u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430\ + \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ + ." + type: integer + message_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ + \u043A\u0430\u0442\u043E\u0440 \u0441\u043E\u043E\u0431\u0449\ + \u0435\u043D\u0438\u044F, \u043A \u043A\u043E\u0442\u043E\ + \u0440\u043E\u043C\u0443 \u0431\u044B\u043B \u0441\u043E\ + \u0437\u0434\u0430\u043D \u0442\u0440\u0435\u0434." + type: integer + updated_at: + description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\ + \u0435\u043C\u044F \u043E\u0431\u043D\u043E\u0432\u043B\u0435\ + \u043D\u0438\u044F \u0442\u0440\u0435\u0434\u0430 (ISO-8601,\ + \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435\ + \ YYYY-MM-DDThh:mm:ss.sssZ.\n" + format: date-time + type: string + type: object + type: object + description: "\u0422\u0440\u0435\u0434 \u0443\u0441\u043F\u0435\u0448\u043D\ + \u043E \u0441\u043E\u0437\u0434\u0430\u043D \u0438\u043B\u0438 \u0432\u043E\ + \u0437\u0432\u0440\u0430\u0449\u0435\u043D\u044B \u0434\u0430\u043D\u043D\ + \u044B\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\ + \u0435\u0433\u043E \u0442\u0440\u0435\u0434\u0430." + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + description: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441." + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\ + \u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E." + summary: "\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u043E\u0432\ + \u043E\u0433\u043E \u0442\u0440\u0435\u0434\u0430" + tags: + - comments + /profile/status: + delete: + description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\ + \u043F\u0440\u043E\u0441\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\ + \u0443\u044E\u0442\n" + operationId: delStatus + responses: + '204': + content: {} + description: "\u041E\u0431\u044A\u0435\u043A\u0442 \u0443\u0441\u043F\u0435\ + \u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D, \u0442\u0435\u043B\ + \u043E \u043E\u0442\u0432\u0435\u0442\u0430 \u043E\u0442\u0441\u0443\u0442\ + \u0441\u0442\u0432\u0443\u0435\u0442" + summary: "\u0443\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0441\u0432\u043E\ + \u0435\u0433\u043E \u0441\u0442\u0430\u0442\u0443\u0441\u0430" + tags: + - status + get: + description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\ + \u043F\u0440\u043E\u0441\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\ + \u0443\u044E\u0442\n" + operationId: getStatus + responses: + '200': + content: + application/json: + schema: + properties: + data: + $ref: '#/components/schemas/Status' + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0438\u043D\ + \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0441\u0432\u043E\ + \u0435\u043C \u0441\u0442\u0430\u0442\u0443\u0441\u0435" + tags: + - status + put: + description: "\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u043E\u0432\ + \u043E\u0433\u043E \u0441\u0442\u0430\u0442\u0443\u0441\u0430.\n" + operationId: putStatus + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/QueryStatus' + required: true + responses: + '201': + content: + application/json: + schema: + properties: + data: + $ref: '#/components/schemas/Status' + type: object + description: "\u041E\u0431\u044A\u0435\u043A\u0442 \u0441\u043E\u0437\u0434\ + \u0430\u043D" + '400': + content: + application/json: + examples: + BLANK: + description: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ + \u043D\u043E\u0435 \u043F\u043E\u043B\u0435 (\u043D\u0435 \u043C\ + \u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\ + \u0441\u0442\u044B\u043C)" + summary: blank + value: + detail: BLANK + INVALID: + description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u0441\u043E\ + \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ + \ \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C (\u043F\u043E\ + \u044F\u0441\u043D\u0435\u043D\u0438\u044F \u0432\u044B \u043F\ + \u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u0432 \u043F\u043E\ + \u043B\u0435 message)" + summary: invalid + value: + detail: INVALID + TOO_LONG: + description: "\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\ + \u0438\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\ + \u0438\u0435 (\u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\ + \u044F \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\ + \u0435 \u0432 \u043F\u043E\u043B\u0435 message)" + summary: too_long + value: + detail: TOO_LONG + WRONG_EMOJI: + description: "Emoji \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043D\ + \u0435 \u043C\u043E\u0436\u0435\u0442 \u0441\u043E\u0434\u0435\ + \u0440\u0436\u0430\u0442\u044C \u0437\u043D\u0430\u0447\u0435\u043D\ + \u0438\u044F \u043E\u0442\u043B\u0438\u0447\u043D\u044B\u0435\ + \ \u043E\u0442 Emoji \u0441\u0438\u043C\u0432\u043E\u043B\u0430" + summary: wrong_emoji + value: + detail: WRONG_EMOJI + schema: + $ref: '#/components/schemas/BadRequest' + description: BadRequest + summary: "\u043D\u043E\u0432\u044B\u0439 \u0441\u0442\u0430\u0442\u0443\u0441" + tags: + - status + /tasks: + post: + description: "\u041F\u0440\u0438 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0438\ + \ \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F \u043E\ + \u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0443\u0441\ + \u043B\u043E\u0432\u0438\u0435\u043C \u044F\u0432\u043B\u044F\u0435\u0442\u0441\ + \u044F \u0443\u043A\u0430\u0437\u0430\u043D\u0438\u044F \u0442\u0438\u043F\ + \u0430 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F\ + : \u0437\u0432\u043E\u043D\u043E\u043A, \u0432\u0441\u0442\u0440\u0435\u0447\ + \u0430, \u043F\u0440\u043E\u0441\u0442\u043E\u0435 \u043D\u0430\u043F\u043E\ + \u043C\u0438\u043D\u0430\u043D\u0438\u0435, \u0441\u043E\u0431\u044B\u0442\ + \u0438\u0435 \u0438\u043B\u0438 \u043F\u0438\u0441\u044C\u043C\u043E. \n\u041F\ + \u0440\u0438 \u044D\u0442\u043E\u043C \u043D\u0435 \u0442\u0440\u0435\u0431\ + \u0443\u0435\u0442\u0441\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\ + \u0435\u043B\u044C\u043D\u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\ + \u0435 - \u0432\u044B \u043F\u0440\u043E\u0441\u0442\u043E \u0441\u043E\u0437\ + \u0434\u0430\u0434\u0438\u0442\u0435 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\ + \u0430\u043D\u0438\u0435 \u0441 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\ + \u0441\u0442\u0432\u0443\u044E\u0449\u0438\u043C \u0442\u0435\u043A\u0441\u0442\ + \u043E\u043C.\n\u0415\u0441\u043B\u0438 \u0432\u044B \u0443\u043A\u0430\u0436\ + \u0438\u0442\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043D\ + \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F - \u0442\u043E\ + \ \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u043D\u043E \u0438 \u0441\u0442\ + \u0430\u043D\u0435\u0442 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u043D\ + \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F.\n\u0423 \u043D\ + \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F \u0434\u043E\u043B\ + \u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u0442\u0432\u0435\u0442\ + \u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435, \u0435\u0441\u043B\u0438\ + \ \u0438\u0445 \u043D\u0435 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0442\ + \u044C - \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043D\u043D\ + \u044B\u043C \u043D\u0430\u0437\u043D\u0430\u0447\u0430\u0435\u0442\u0435\u0441\ + \u044C \u0432\u044B.\n" + operationId: createTask + requestBody: + content: + application/json: + schema: + properties: + task: + properties: + content: + description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ + \ \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\ + \u044F" + type: string + custom_properties: + items: + properties: + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\ + \u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\ + \u044F" + type: integer + value: + description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ + \u0435 \u043F\u043E\u043B\u044F" + type: string + type: object + type: array + due_at: + description: "\u0421\u0440\u043E\u043A \u0432\u044B\u043F\u043E\ + \u043B\u043D\u0435\u043D\u0438\u044F \u043D\u0430\u043F\u043E\ + \u043C\u0438\u043D\u0430\u043D\u0438\u044F (ISO-8601)" + format: date-time + type: string + kind: + description: "\u0422\u0438\u043F \u043D\u0430\u043F\u043E\u043C\ + \u0438\u043D\u0430\u043D\u0438\u044F (call, meeting, reminder,\ + \ event, email)" + type: string + performer_ids: + description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\ + \u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440\u043E\u0432 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\ + \u0430\u0442\u0435\u043B\u0435\u0439" + items: + type: integer + type: array + priority: + description: "\u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\ + \u0442 (1 - \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\ + \u043D\u0438\u044E, 2 - \u0432\u0430\u0436\u043D\u043E, 3\ + \ - \u043E\u0447\u0435\u043D\u044C \u0432\u0430\u0436\u043D\ + \u043E)" + type: integer + required: + - kind + - content + - due_at + type: object + type: object + required: true + responses: + '201': + content: + application/json: + schema: + properties: + data: + properties: + content: + description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435" + type: string + created_at: + description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\ + \u0435\u043C\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\ + \u044F" + format: date-time + type: string + custom_properties: + items: + properties: + data_type: + description: "\u0422\u0438\u043F \u043F\u043E\u043B\u044F\ + \ (string, number, date \u0438\u043B\u0438 link)" + type: string + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\ + \u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\ + \u044F" + type: integer + name: + description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\ + \u0435 \u043F\u043E\u043B\u044F" + type: string + value: + description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ + \u0435" + type: string + type: object + type: array + due_at: + description: "\u0421\u0440\u043E\u043A \u0432\u044B\u043F\u043E\ + \u043B\u043D\u0435\u043D\u0438\u044F (ISO-8601)" + format: date-time + type: string + id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ + \u043A\u0430\u0442\u043E\u0440 \u0441\u043E\u0437\u0434\u0430\ + \u043D\u043D\u043E\u0433\u043E \u043D\u0430\u043F\u043E\u043C\ + \u0438\u043D\u0430\u043D\u0438\u044F" + type: integer + kind: + description: "\u0422\u0438\u043F" + type: string + performer_ids: + items: + type: integer + type: array + priority: + description: "\u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\ + \u0442" + type: integer + status: + description: "\u0421\u0442\u0430\u0442\u0443\u0441 \u043D\u0430\ + \u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F" + type: string + user_id: + description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ + \u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\ + \u043E\u0432\u0430\u0442\u0435\u043B\u044F-\u0441\u043E\u0437\ + \u0434\u0430\u0442\u0435\u043B\u044F" + type: integer + type: object + type: object + description: "\u041D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\ + \u0435 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0441\u043E\u0437\u0434\ + \u0430\u043D\u043E" + '400': + content: + application/json: + schema: + properties: + error: + description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ + \ \u043E\u0448\u0438\u0431\u043A\u0438" + type: string + type: object + description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u043F\u0440\ + \u043E\u0441\u0430" + summary: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0441\u043E\u0437\ + \u0434\u0430\u043D\u0438\u044F \u043D\u043E\u0432\u043E\u0433\u043E \u043D\ + \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F." + tags: + - reminders + /uploads: + post: + description: "\u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043F\ + \u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B, \u043D\u0435\u043E\u0431\ + \u0445\u043E\u0434\u0438\u043C\u044B\u0435 \u0434\u043B\u044F \u0431\u0435\ + \u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0439 \u0437\u0430\u0433\u0440\u0443\ + \u0437\u043A\u0438 \u0444\u0430\u0439\u043B\u0430." + operationId: getUploads + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u043E\u0442\ + \u0432\u0435\u0442." + summary: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\ + \u0434\u043F\u0438\u0441\u0438 \u0438 \u043A\u043B\u044E\u0447\u0430 \u0434\ + \u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0444\u0430\ + \u0439\u043B\u0430" + tags: + - common methods + /users: + get: + description: 'Fetch a paginated list of employees with optional filtering by + query. + + ' + operationId: getEmployees + parameters: + - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ + \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ + \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ + \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ + \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\ + \u0438\u043C\u0443\u043C" + in: query + name: per + required: false + schema: + default: 50 + maximum: 50 + type: integer + - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ + \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ + \u0430\u043D\u0438\u044E 1)" + in: query + name: page + required: false + schema: + default: 1 + type: integer + - description: "\u041F\u043E\u0438\u0441\u043A\u043E\u0432\u0430\u044F \u0444\ + \u0440\u0430\u0437\u0430 \u0434\u043B\u044F \u0444\u0438\u043B\u044C\u0442\ + \u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\ + \u0430\u0442\u043E\u0432 (\u043F\u043E\u0438\u0441\u043A \u0438\u0434\u0435\ + \u0442 \u043F\u043E \u043F\u043E\u043B\u044F\u043C first_name (\u0438\u043C\ + \u044F), last_name (\u0444\u0430\u043C\u0438\u043B\u0438\u044F),\nemail\ + \ (\u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\u044F \u043F\ + \u043E\u0447\u0442\u0430), phone_number (\u0442\u0435\u043B\u0435\u0444\u043E\ + \u043D) \u0438 nickname (\u043D\u0438\u043A\u043D\u0435\u0439\u043C))\n" + in: query + name: query + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + properties: + data: + items: + $ref: '#/components/schemas/Employee' + type: array + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0430\u043A\ + \u0442\u0443\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\ + \u043A\u0430 \u0432\u0441\u0435\u0445 \u0441\u043E\u0442\u0440\u0443\u0434\ + \u043D\u0438\u043A\u043E\u0432 \u043A\u043E\u043C\u043F\u0430\u043D\u0438\u0438" + tags: + - employees + /users/{id}: + get: + description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ + \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0438\u043D\u0444\u043E\u0440\u043C\ + \u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u0442\u0440\u0443\u0434\u043D\ + \u0438\u043A\u0435.\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\ + \u043D\u0438\u044F \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0430\ + \ \u0432\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\ + \u043E \u0437\u043D\u0430\u0442\u044C \u0435\u0433\u043E id \u0438 \u0443\u043A\ + \u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\ + \u0440\u043E\u0441\u0430.\n" + operationId: getEmployee + parameters: + - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ + \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ + \u0440 \u0441\u043E\u0442\u0440\u0443\u0434\u043A\u0438\u043A\u0430" + in: path + name: id + required: true + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + properties: + data: + $ref: '#/components/schemas/Employee' + type: object + description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ + \u043F\u0440\u043E\u0441" + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + description: "\u0421\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A \u043D\ + \u0435 \u043D\u0430\u0439\u0434\u0435\u043D" + summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0438\u043D\ + \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u0442\ + \u0440\u0443\u0434\u043D\u0438\u043A\u0435" + tags: + - employees +security: +- bearerAuth: [] +servers: +- url: https://api.pachca.com/api/shared/v1 +tags: +- description: Everything about common methods + name: common methods +- description: Everything about employees + name: employees +- description: Everything about status + name: status +- description: Everything about tags + name: tags +- description: Everything about chats and channels + name: chats and channels +- description: Everything about talk and channel participants + name: talk and channel participants +- description: Everything about comments + name: comments +- description: Everything about messages + name: messages +- description: Everything about reactions to messages + name: reactions to messages +- description: Everything about reminders + name: reminders +x-base-url: https://api.pachca.com/api/shared/v1 diff --git a/src/generator1/script.py b/src/generator1/script.py index 9a504f9..3b71cab 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,8 +1,101 @@ +# import ast +# import os +# import subprocess + +# import yaml +# from jinja2 import Environment, FileSystemLoader + + +# def extract_functions_and_imports_from_file(file_path) -> None: +# with open(file_path, "r", encoding="utf-8") as file: +# tree = ast.parse(file.read()) + +# functions = [] +# imports = [] + +# for node in ast.walk(tree): +# if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, +# ast.FunctionDef): +# functions.append(ast.unparse(node)) +# elif isinstance(node, ast.ImportFrom): +# # Убираем пробел после 'from' и обрабатываем импорты +# module = node.module if node.module else '' +# if module.startswith('.'): +# module = module[1:] # Убираем точку в начале +# for alias in node.names: +# if module == 'typing' or module == 'http': +# imports.append(f"from {module} import {alias.name}") +# else: +# imports.append(f"from .{module} import {alias.name}") + +# return functions, imports + + +# def get_all_api_functions_and_imports(api_dir): +# all_functions = [] +# all_imports = [] +# for root, _, files in os.walk(api_dir): +# for file in files: +# if file.endswith(".py"): +# file_path = os.path.join(root, file) +# functions, imports = extract_functions_and_imports_from_file(file_path) +# all_functions.extend(functions) +# all_imports.extend(imports) +# return all_functions, all_imports + + +# def create_modified_openapi_yaml(input_path, output_path): +# with open(input_path, "r", encoding="utf-8") as file: +# openapi_data = yaml.safe_load(file) +# base_url = openapi_data.get("servers", [{}])[0].get("url") +# openapi_data["x-base-url"] = base_url + +# with open(output_path, "w", encoding="utf-8") as file: +# yaml.dump(openapi_data, file) + +# return base_url + + +# def generate_client(openapi_path, templates_path): +# command = [ +# "openapi-python-client", +# "generate", +# "--path", openapi_path, +# "--custom-template-path", templates_path, +# "--overwrite" +# ] +# subprocess.run(command, check=True) + + +# def process_generated_client(api_dir, client_template_path, client_output_path, base_url): +# endpoints, imports = get_all_api_functions_and_imports(api_dir) + +# env = Environment(loader=FileSystemLoader('templates')) +# client_template = env.get_template(client_template_path) + +# with open(client_output_path, mode='w', encoding="utf-8") as file: +# # Объединяем импорты в одну строку +# unique_imports = list(set(imports)) # Убираем дубликаты +# file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл +# file.write(client_template.render(endpoints=endpoints, base_url=base_url)) + + +# openapi_input_path = "openapi.yaml" +# openapi_modified_path = "openapi_modified.yaml" +# templates_path = "./templates" +# api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" +# client_template_name = "client.py.jinja" +# client_output_path = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" + +# # Выполнение шагов +# base_url = create_modified_openapi_yaml(openapi_input_path, openapi_modified_path) +# generate_client(openapi_modified_path, templates_path) +# process_generated_client(api_dir, client_template_name, client_output_path, base_url) + import ast import os -import yaml -import subprocess +import yaml from jinja2 import Environment, FileSystemLoader @@ -44,50 +137,27 @@ def get_all_api_functions_and_imports(api_dir): return all_functions, all_imports -def create_modified_openapi_yaml(input_path, output_path): - with open(input_path, "r", encoding="utf-8") as file: - openapi_data = yaml.safe_load(file) - base_url = openapi_data.get("servers", [{}])[0].get("url") - openapi_data["x-base-url"] = base_url - - with open(output_path, "w", encoding="utf-8") as file: - yaml.dump(openapi_data, file) - - return base_url +def get_base_url_from_yaml(openapi_yaml): + with open(openapi_yaml, "r", encoding="utf-8") as file: + data = yaml.safe_load(file) + return data['servers'][0]['url'] -def generate_client(openapi_path, templates_path): - command = [ - "openapi-python-client", - "generate", - "--path", openapi_path, - "--custom-template-path", templates_path, - "--overwrite" - ] - subprocess.run(command, check=True) - - -def process_generated_client(api_dir, client_template_path, client_output_path, base_url): - endpoints, imports = get_all_api_functions_and_imports(api_dir) - - env = Environment(loader=FileSystemLoader('templates')) - client_template = env.get_template(client_template_path) +api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" +openapi_yaml = "openapi.yaml" +endpoints, imports = get_all_api_functions_and_imports(api_dir) +base_url = get_base_url_from_yaml(openapi_yaml) - with open(client_output_path, mode='w', encoding="utf-8") as file: - # Объединяем импорты в одну строку - unique_imports = list(set(imports)) # Убираем дубликаты - file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл - file.write(client_template.render(endpoints=endpoints, base_url=base_url)) +env = Environment( + loader=FileSystemLoader('templates'), +) +client_template = env.get_template('client.py.jinja') -openapi_input_path = "openapi.yaml" -openapi_modified_path = "openapi_modified.yaml" -templates_path = "./templates" -api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -client_template_name = "client.py.jinja" -client_output_path = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" +client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' -# Выполнение шагов -base_url = create_modified_openapi_yaml(openapi_input_path, openapi_modified_path) -generate_client(openapi_modified_path, templates_path) -process_generated_client(api_dir, client_template_name, client_output_path, base_url) +with open(client_path, mode='w', encoding="utf-8") as file: + # Объединяем импорты в одну строку + unique_imports = list(set(imports)) # Убираем дубликаты + file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл + file.write(client_template.render(endpoints=endpoints, base_url=base_url)) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index ee735e6..e35a6ec 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -269,7 +269,7 @@ class Pachca: def __init__(self, token): self.client = AuthenticatedClient(token=token) - + self.base_url = '{{ base_url }}' {% if endpoints %} {% for endpoint in endpoints %} {{ endpoint | indent(4, first=Fasle) }} From a956181049876857ec3bc702036efeef4d34927e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 22:21:22 +0300 Subject: [PATCH 108/296] client_servis.py --- src/generator1/client_servis.py | 134 ++ src/generator1/pachca.py | 8 +- src/generator1/pachca_servis/.gitignore | 23 + src/generator1/pachca_servis/README.md | 124 ++ .../__init__.py | 8 + .../api/__init__.py | 1 + .../api/chats_and_channels/__init__.py | 0 .../api/chats_and_channels/create_chat.py | 97 ++ .../api/chats_and_channels/get_chat.py | 74 + .../api/chats_and_channels/get_chats.py | 142 ++ .../api/comments/__init__.py | 0 .../api/comments/create_thread.py | 83 ++ .../api/common_methods/__init__.py | 0 .../api/common_methods/get_common_methods.py | 85 ++ .../api/common_methods/get_direct_url.py | 45 + .../api/common_methods/get_uploads.py | 61 + .../api/employees/__init__.py | 0 .../api/employees/get_employee.py | 74 + .../api/employees/get_employees.py | 87 ++ .../api/message/__init__.py | 0 .../api/message/edit_message.py | 104 ++ .../api/messages/__init__.py | 0 .../api/messages/create_message.py | 108 ++ .../api/messages/get_list_message.py | 106 ++ .../api/messages/get_message.py | 75 + .../api/reactions_to_messages/__init__.py | 0 .../delete_message_reactions.py | 92 ++ .../get_message_reactions.py | 96 ++ .../post_message_reactions.py | 106 ++ .../api/reminders/__init__.py | 0 .../api/reminders/create_task.py | 91 ++ .../api/status/__init__.py | 0 .../api/status/del_status.py | 36 + .../api/status/get_status.py | 61 + .../api/status/put_status.py | 82 ++ .../api/tags/__init__.py | 0 .../api/tags/get_tag.py | 73 + .../api/tags/get_tags.py | 86 ++ .../api/tags/get_tags_employees.py | 94 ++ .../talk_and_channel_participants/__init__.py | 0 .../leave_chat.py | 85 ++ .../post_members_to_chats.py | 89 ++ .../post_tags_to_chats.py | 89 ++ .../pachca_api_open_api_3_0_client/client.py | 1223 +++++++++++++++++ .../pachca_api_open_api_3_0_client/errors.py | 16 + .../models/__init__.py | 189 +++ .../models/bad_request.py | 67 + .../models/base_employee.py | 186 +++ .../base_employee_custom_properties_item.py | 85 ++ .../models/button.py | 78 ++ .../models/chat.py | 162 +++ .../models/create_chat_body.py | 71 + .../models/create_chat_response_201.py | 71 + .../models/create_chat_response_400.py | 74 + .../models/create_chat_response_404.py | 74 + .../models/create_chat_response_422.py | 74 + .../models/create_message.py | 178 +++ .../models/create_message_body.py | 71 + .../models/create_message_entity_type.py | 10 + .../models/create_message_files_item.py | 84 ++ .../create_message_files_item_file_type.py | 9 + .../models/create_message_response_201.py | 71 + .../models/create_task_body.py | 71 + .../models/create_task_body_task.py | 123 ++ ...e_task_body_task_custom_properties_item.py | 67 + .../models/create_task_response_201.py | 71 + .../models/create_task_response_201_data.py | 179 +++ ...esponse_201_data_custom_properties_item.py | 85 ++ .../models/create_task_response_400.py | 58 + .../models/create_thread_response_200.py | 71 + .../models/create_thread_response_200_data.py | 104 ++ .../delete_message_reactions_response_400.py | 76 + ...sage_reactions_response_400_errors_item.py | 111 ++ ...ctions_response_400_errors_item_payload.py | 43 + .../delete_message_reactions_response_404.py | 76 + ...sage_reactions_response_404_errors_item.py | 111 ++ ...ctions_response_404_errors_item_payload.py | 43 + .../models/direct_response.py | 195 +++ .../models/edit_message_body.py | 72 + .../models/edit_message_response_200.py | 74 + .../models/edit_messages.py | 113 ++ .../models/edit_messages_buttons_item_item.py | 76 + .../models/edit_messages_files.py | 95 ++ .../models/edit_messages_files_file_type.py | 9 + .../models/employee.py | 275 ++++ .../models/error.py | 107 ++ .../models/error_payload.py | 43 + .../models/errors_code.py | 108 ++ .../models/errors_code_payload.py | 43 + .../models/file_response.py | 130 ++ .../models/get_chat_response_200.py | 71 + .../models/get_chat_response_404.py | 74 + .../models/get_chats_availability.py | 9 + .../models/get_chats_response_200.py | 74 + .../models/get_chats_response_400.py | 71 + .../models/get_chats_response_404.py | 74 + .../models/get_chats_response_422.py | 74 + .../models/get_chats_sortid.py | 9 + .../models/get_common_methods_response_200.py | 74 + .../models/get_employee_response_200.py | 71 + .../models/get_employees_response_200.py | 74 + .../models/get_list_message_response_200.py | 74 + .../models/get_message_reactions_body.py | 68 + .../get_message_reactions_response_200.py | 74 + .../models/get_message_response_200.py | 71 + .../models/get_status_response_200.py | 88 ++ .../models/get_tag_response_200.py | 71 + .../models/get_tag_response_404.py | 74 + .../get_tag_response_404_errors_item.py | 107 ++ ...et_tag_response_404_errors_item_payload.py | 43 + .../models/get_tags_employees_response_200.py | 74 + .../models/get_tags_response_200.py | 74 + .../models/get_tags_response_400.py | 74 + .../get_tags_response_400_errors_item.py | 107 ++ ...t_tags_response_400_errors_item_payload.py | 43 + .../models/message.py | 272 ++++ .../models/message_entity_type.py | 10 + .../models/message_files_item.py | 104 ++ .../models/message_files_item_file_type.py | 9 + .../models/message_forwarding.py | 153 +++ .../models/message_thread.py | 67 + .../models/not_found.py | 59 + .../models/post_members_to_chats_body.py | 69 + .../models/post_message_reactions_body.py | 58 + .../post_message_reactions_response_400.py | 58 + .../post_message_reactions_response_403.py | 58 + .../post_message_reactions_response_404.py | 58 + .../models/post_tags_to_chats_body.py | 58 + .../models/put_status_response_201.py | 88 ++ .../models/query_chat.py | 91 ++ .../models/query_common_methods.py | 77 ++ .../models/query_status.py | 71 + .../models/query_status_status.py | 102 ++ .../models/reaction.py | 86 ++ .../models/status_type_0.py | 101 ++ .../models/tag.py | 77 ++ .../pachca_api_open_api_3_0_client/py.typed | 1 + .../pachca_api_open_api_3_0_client/types.py | 46 + src/generator1/pachca_servis/pyproject.toml | 27 + src/generator1/script.py | 110 +- src/generator1/templates/client.py.jinja | 263 +--- 141 files changed, 11550 insertions(+), 281 deletions(-) create mode 100644 src/generator1/client_servis.py create mode 100644 src/generator1/pachca_servis/.gitignore create mode 100644 src/generator1/pachca_servis/README.md create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py create mode 100644 src/generator1/pachca_servis/pyproject.toml diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py new file mode 100644 index 0000000..fae0ea2 --- /dev/null +++ b/src/generator1/client_servis.py @@ -0,0 +1,134 @@ +import ssl +from typing import Any, Optional, Union + +import httpx +from attrs import define, evolve, field + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(default="https://api.pachca.com/api/shared/v1", kw_only=True, alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index bf5bef7..5eed0a1 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -1,10 +1,8 @@ import asyncio -from pachca_api_open_api_3_0_client.client import Pachca -from pachca_api_open_api_3_0_client.models.create_chat_body import ( - CreateChatBody, -) -from pachca_api_open_api_3_0_client.models.query_chat import QueryChat +from pachca_servis.pachca_api_open_api_3_0_client.client import Pachca +from pachca_servis.pachca_api_open_api_3_0_client.models.create_chat_body import CreateChatBody +from pachca_servis.pachca_api_open_api_3_0_client.models.query_chat import QueryChat query_chat = QueryChat(name='test') chat_body = CreateChatBody(chat=query_chat) diff --git a/src/generator1/pachca_servis/.gitignore b/src/generator1/pachca_servis/.gitignore new file mode 100644 index 0000000..79a2c3d --- /dev/null +++ b/src/generator1/pachca_servis/.gitignore @@ -0,0 +1,23 @@ +__pycache__/ +build/ +dist/ +*.egg-info/ +.pytest_cache/ + +# pyenv +.python-version + +# Environments +.env +.venv + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# JetBrains +.idea/ + +/coverage.xml +/.coverage diff --git a/src/generator1/pachca_servis/README.md b/src/generator1/pachca_servis/README.md new file mode 100644 index 0000000..3bb71ab --- /dev/null +++ b/src/generator1/pachca_servis/README.md @@ -0,0 +1,124 @@ +# pachca-api-open-api-3-0-client +A client library for accessing PachcaAPI - OpenAPI 3.0 + +## Usage +First, create a client: + +```python +from pachca_api_open_api_3_0_client import Client + +client = Client(base_url="https://api.example.com") +``` + +If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: + +```python +from pachca_api_open_api_3_0_client import AuthenticatedClient + +client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") +``` + +Now call your endpoint and use your models: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +with client as client: + my_data: MyDataModel = get_my_data_model.sync(client=client) + # or if you need more info (e.g. status_code) + response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) +``` + +Or do the same thing with an async version: + +```python +from pachca_api_open_api_3_0_client.models import MyDataModel +from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model +from pachca_api_open_api_3_0_client.types import Response + +async with client as client: + my_data: MyDataModel = await get_my_data_model.asyncio(client=client) + response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) +``` + +By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl="/path/to/certificate_bundle.pem", +) +``` + +You can also disable certificate validation altogether, but beware that **this is a security risk**. + +```python +client = AuthenticatedClient( + base_url="https://internal_api.example.com", + token="SuperSecretToken", + verify_ssl=False +) +``` + +Things to know: +1. Every path/method combo becomes a Python module with four functions: + 1. `sync`: Blocking request that returns parsed data (if successful) or `None` + 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. + 1. `asyncio`: Like `sync` but async instead of blocking + 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking + +1. All path/query params, and bodies become method arguments. +1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) +1. Any endpoint which did not have a tag will be in `pachca_api_open_api_3_0_client.api.default` + +## Advanced customizations + +There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): + +```python +from pachca_api_open_api_3_0_client import Client + +def log_request(request): + print(f"Request event hook: {request.method} {request.url} - Waiting for response") + +def log_response(response): + request = response.request + print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") + +client = Client( + base_url="https://api.example.com", + httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, +) + +# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() +``` + +You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): + +```python +import httpx +from pachca_api_open_api_3_0_client import Client + +client = Client( + base_url="https://api.example.com", +) +# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. +client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) +``` + +## Building / publishing this package +This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: +1. Update the metadata in pyproject.toml (e.g. authors, version) +1. If you're using a private repository, configure it with Poetry + 1. `poetry config repositories. ` + 1. `poetry config http-basic. ` +1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` + +If you want to install this client into another project without publishing it (e.g. for development) then: +1. If that project **is using Poetry**, you can simply do `poetry add ` from that project +1. If that project is not using Poetry: + 1. Build a wheel with `poetry build -f wheel` + 1. Install that wheel from the other project `pip install ` diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py new file mode 100644 index 0000000..3a6c9f0 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py @@ -0,0 +1,8 @@ +"""A client library for accessing PachcaAPI - OpenAPI 3.0""" + +from .client import AuthenticatedClient, Client + +__all__ = ( + "AuthenticatedClient", + "Client", +) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py new file mode 100644 index 0000000..81f9fa2 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py @@ -0,0 +1 @@ +"""Contains methods for accessing the API""" diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py new file mode 100644 index 0000000..89cdc5a --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -0,0 +1,97 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.create_chat_body import CreateChatBody +from ...models.create_chat_response_201 import CreateChatResponse201 +from ...models.create_chat_response_400 import CreateChatResponse400 +from ...models.create_chat_response_404 import CreateChatResponse404 +from ...models.create_chat_response_422 import CreateChatResponse422 +from ...types import Response + + +def _get_kwargs_createChat( + self, + body: CreateChatBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/chats", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_createChat( + self, response: httpx.Response +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + + return response_422 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createChat( + self, response: httpx.Response +) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_createChat(response=response), + ) + + +async def createChat( + self, + body: CreateChatBody, +) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + r""" Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + + kwargs = self._get_kwargs_createChat( + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_createChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py new file mode 100644 index 0000000..e134dd6 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -0,0 +1,74 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_chat_response_200 import GetChatResponse200 +from ...models.get_chat_response_404 import GetChatResponse404 +from ...types import Response + + +def _get_kwargs_getChat( + self, + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/chats/{id}", + } + + return _kwargs + + +def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getChat(response=response), + ) + + +async def getChat( + self, + id: int, +) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + + kwargs = self._get_kwargs_getChat( + id=id, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py new file mode 100644 index 0000000..bebb456 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -0,0 +1,142 @@ +import datetime +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_chats_availability import GetChatsAvailability +from ...models.get_chats_response_200 import GetChatsResponse200 +from ...models.get_chats_response_400 import GetChatsResponse400 +from ...models.get_chats_response_404 import GetChatsResponse404 +from ...models.get_chats_response_422 import GetChatsResponse422 +from ...models.get_chats_sortid import GetChatsSortid +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getChats( + self, + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + + params["sort[id]"] = json_sortid + + params["per"] = per + + params["page"] = page + + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + + params["availability"] = json_availability + + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params["last_message_at_after"] = json_last_message_at_after + + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params["last_message_at_before"] = json_last_message_at_before + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/chats", + "params": params, + } + + return _kwargs + + +def _parse_response_getChats( + self, response: httpx.Response +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + + return response_422 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getChats( + self, response: httpx.Response +) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getChats(response=response), + ) + + +async def getChats( + self, + sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, + availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, + last_message_at_after: Union[Unset, datetime.datetime] = UNSET, + last_message_at_before: Union[Unset, datetime.datetime] = UNSET, +) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + + kwargs = self._get_kwargs_getChats( + sortid=sortid, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py new file mode 100644 index 0000000..eb23656 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -0,0 +1,83 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.create_thread_response_200 import CreateThreadResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_createThread( + self, + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/thread", + } + + return _kwargs + + +def _parse_response_createThread( + self, response: httpx.Response +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createThread( + self, response: httpx.Response +) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_createThread(response=response), + ) + + +async def createThread( + self, + id: int, +) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + + kwargs = self._get_kwargs_createThread( + id=id, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_createThread(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py new file mode 100644 index 0000000..7eeb703 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -0,0 +1,85 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 +from ...types import UNSET, Response + + +def _get_kwargs_getCommonMethods( + self, + entity_type: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["entity_type"] = entity_type + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/custom_properties", + "params": params, + } + + return _kwargs + + +def _parse_response_getCommonMethods( + self, response: httpx.Response +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getCommonMethods( + self, response: httpx.Response +) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getCommonMethods(response=response), + ) + + +async def getCommonMethods( + self, + entity_type: str, +) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + + kwargs = self._get_kwargs_getCommonMethods( + entity_type=entity_type, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getCommonMethods(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py new file mode 100644 index 0000000..49b24c6 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py @@ -0,0 +1,45 @@ +from http import HTTPStatus +from typing import Any, Optional + +import httpx + +from ... import errors +from ...models.direct_response import DirectResponse +from ...types import Response + + +def _get_kwargs_getDirectUrl( + self, + body: DirectResponse, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/direct_url", + } + + _body = body.to_multipart() + + _kwargs["files"] = _body + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getDirectUrl(response=response), + ) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py new file mode 100644 index 0000000..b5ddcd3 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -0,0 +1,61 @@ +from http import HTTPStatus +from typing import Any, Optional + +import httpx + +from ... import errors +from ...models.file_response import FileResponse +from ...types import Response + + +def _get_kwargs_getUploads( + self, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/uploads", + } + + return _kwargs + + +def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getUploads(response=response), + ) + + +async def getUploads( + self, +) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + + kwargs = self._get_kwargs_getUploads() + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getUploads(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py new file mode 100644 index 0000000..5f758db --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -0,0 +1,74 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_employee_response_200 import GetEmployeeResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_getEmployee( + self, + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/users/{id}", + } + + return _kwargs + + +def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getEmployee(response=response), + ) + + +async def getEmployee( + self, + id: int, +) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + + kwargs = self._get_kwargs_getEmployee( + id=id, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getEmployee(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py new file mode 100644 index 0000000..d68f825 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -0,0 +1,87 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_employees_response_200 import GetEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getEmployees( + self, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params["query"] = query + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/users", + "params": params, + } + + return _kwargs + + +def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getEmployees(response=response), + ) + + +async def getEmployees( + self, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, + query: Union[Unset, str] = UNSET, +) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + + kwargs = self._get_kwargs_getEmployees( + per=per, + page=page, + query=query, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getEmployees(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py new file mode 100644 index 0000000..9f4b705 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py @@ -0,0 +1,104 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.edit_message_body import EditMessageBody +from ...models.edit_message_response_200 import EditMessageResponse200 +from ...models.errors_code import ErrorsCode +from ...types import Response + + +def _get_kwargs_editMessage( + self, + id: int, + body: EditMessageBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": f"/messages/{id}", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_editMessage( + self, response: httpx.Response +) -> Optional[Union[EditMessageResponse200, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = EditMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_editMessage( + self, response: httpx.Response +) -> Response[Union[EditMessageResponse200, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_editMessage(response=response), + ) + + +async def editMessage( + self, + id: int, + body: EditMessageBody, +) -> Optional[Union[EditMessageResponse200, list["ErrorsCode"]]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (EditMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[EditMessageResponse200, list['ErrorsCode']] + """ + + kwargs = self._get_kwargs_editMessage( + id=id, + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_editMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py new file mode 100644 index 0000000..89fccb4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -0,0 +1,108 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.create_message_body import CreateMessageBody +from ...models.create_message_response_201 import CreateMessageResponse201 +from ...models.error import Error +from ...types import Response + + +def _get_kwargs_createMessage( + self, + body: CreateMessageBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/messages", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_createMessage( + self, response: httpx.Response +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + response_404.append(componentsschemas_errors_item) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createMessage( + self, response: httpx.Response +) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_createMessage(response=response), + ) + + +async def createMessage( + self, + body: CreateMessageBody, +) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: + r"""создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \"discussion\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \"user\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + + kwargs = self._get_kwargs_createMessage( + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_createMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py new file mode 100644 index 0000000..090f093 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -0,0 +1,106 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.get_list_message_response_200 import GetListMessageResponse200 +from ...models.not_found import NotFound +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getListMessage( + self, + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["chat_id"] = chat_id + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/messages", + "params": params, + } + + return _kwargs + + +def _parse_response_getListMessage( + self, response: httpx.Response +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetListMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getListMessage( + self, response: httpx.Response +) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getListMessage(response=response), + ) + + +async def getListMessage( + self, + chat_id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + + kwargs = self._get_kwargs_getListMessage( + chat_id=chat_id, + per=per, + page=page, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getListMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py new file mode 100644 index 0000000..83f1f22 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -0,0 +1,75 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_message_response_200 import GetMessageResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_getMessage( + self, + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}", + } + + return _kwargs + + +def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getMessage(response=response), + ) + + +async def getMessage( + self, + id: int, +) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + + kwargs = self._get_kwargs_getMessage( + id=id, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py new file mode 100644 index 0000000..92090b4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -0,0 +1,92 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from ...types import UNSET, Response + + +def _get_kwargs_deleteMessageReactions( + self, + id: int, + code: str, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["code"] = code + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/messages/{id}/reactions", + "params": params, + } + + return _kwargs + + +def _parse_response_deleteMessageReactions( + self, response: httpx.Response +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_deleteMessageReactions( + self, response: httpx.Response +) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_deleteMessageReactions(response=response), + ) + + +async def deleteMessageReactions( + self, + id: int, + code: str, +) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (int): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + + kwargs = self._get_kwargs_deleteMessageReactions( + id=id, + code=code, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_deleteMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py new file mode 100644 index 0000000..e2721f1 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -0,0 +1,96 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.get_message_reactions_body import GetMessageReactionsBody +from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 +from ...models.not_found import NotFound +from ...types import Response + + +def _get_kwargs_getMessageReactions( + self, + id: int, + body: GetMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_getMessageReactions( + self, response: httpx.Response +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getMessageReactions( + self, response: httpx.Response +) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getMessageReactions(response=response), + ) + + +async def getMessageReactions( + self, + id: int, + body: GetMessageReactionsBody, +) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + + kwargs = self._get_kwargs_getMessageReactions( + id=id, + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py new file mode 100644 index 0000000..7386098 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -0,0 +1,106 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...models.post_message_reactions_body import PostMessageReactionsBody +from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 +from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 +from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 +from ...types import Response + + +def _get_kwargs_postMessageReactions( + self, + id: int, + body: PostMessageReactionsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/messages/{id}/reactions", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_postMessageReactions( + self, response: httpx.Response +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + + return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_postMessageReactions( + self, response: httpx.Response +) -> Response[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_postMessageReactions(response=response), + ) + + +async def postMessageReactions( + self, + id: int, + body: PostMessageReactionsBody, +) -> Optional[ + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] +]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (int): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + + kwargs = self._get_kwargs_postMessageReactions( + id=id, + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_postMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py new file mode 100644 index 0000000..726cbf8 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py @@ -0,0 +1,91 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.create_task_body import CreateTaskBody +from ...models.create_task_response_201 import CreateTaskResponse201 +from ...models.create_task_response_400 import CreateTaskResponse400 +from ...types import Response + + +def _get_kwargs_createTask( + self, + body: CreateTaskBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tasks", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_createTask( + self, response: httpx.Response +) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: + if response.status_code == 201: + response_201 = CreateTaskResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = CreateTaskResponse400.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_createTask( + self, response: httpx.Response +) -> Response[Union[CreateTaskResponse201, CreateTaskResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_createTask(response=response), + ) + + +async def createTask( + self, + body: CreateTaskBody, +) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (CreateTaskBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateTaskResponse201, CreateTaskResponse400] + """ + + kwargs = self._get_kwargs_createTask( + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_createTask(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py new file mode 100644 index 0000000..343eec6 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py @@ -0,0 +1,36 @@ +from http import HTTPStatus +from typing import Any, Optional + +import httpx + +from ... import errors +from ...types import Response + + +def _get_kwargs_delStatus( + self, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_delStatus(response=response), + ) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py new file mode 100644 index 0000000..f0ebcd7 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -0,0 +1,61 @@ +from http import HTTPStatus +from typing import Any, Optional + +import httpx + +from ... import errors +from ...models.get_status_response_200 import GetStatusResponse200 +from ...types import Response + + +def _get_kwargs_getStatus( + self, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/profile/status", + } + + return _kwargs + + +def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getStatus(response=response), + ) + + +async def getStatus( + self, +) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + + kwargs = self._get_kwargs_getStatus() + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getStatus(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py new file mode 100644 index 0000000..1211045 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -0,0 +1,82 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.put_status_response_201 import PutStatusResponse201 +from ...models.query_status import QueryStatus +from ...types import Response + + +def _get_kwargs_putStatus( + self, + body: QueryStatus, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/profile/status", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + + return response_201 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_putStatus(response=response), + ) + + +async def putStatus( + self, + body: QueryStatus, +) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + + kwargs = self._get_kwargs_putStatus( + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_putStatus(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py new file mode 100644 index 0000000..4f0b49f --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -0,0 +1,73 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_tag_response_200 import GetTagResponse200 +from ...models.get_tag_response_404 import GetTagResponse404 +from ...types import Response + + +def _get_kwargs_getTag( + self, + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}", + } + + return _kwargs + + +def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getTag(response=response), + ) + + +async def getTag( + self, + id: int, +) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + + kwargs = self._get_kwargs_getTag( + id=id, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getTag(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py new file mode 100644 index 0000000..9710704 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -0,0 +1,86 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.get_tags_response_200 import GetTagsResponse200 +from ...models.get_tags_response_400 import GetTagsResponse400 +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getTags( + self, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/group_tags", + "params": params, + } + + return _kwargs + + +def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getTags(response=response), + ) + + +async def getTags( + self, + per: Union[Unset, int] = 50, + page: Union[Unset, int] = 1, +) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + + kwargs = self._get_kwargs_getTags( + per=per, + page=page, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getTags(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py new file mode 100644 index 0000000..d259ecd --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -0,0 +1,94 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...models.bad_request import BadRequest +from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs_getTagsEmployees( + self, + id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["per"] = per + + params["page"] = page + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/group_tags/{id}/users", + "params": params, + } + + return _kwargs + + +def _parse_response_getTagsEmployees( + self, response: httpx.Response +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_getTagsEmployees( + self, response: httpx.Response +) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_getTagsEmployees(response=response), + ) + + +async def getTagsEmployees( + self, + id: int, + per: Union[Unset, int] = 25, + page: Union[Unset, int] = 1, +) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + + kwargs = self._get_kwargs_getTagsEmployees( + id=id, + per=per, + page=page, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_getTagsEmployees(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py new file mode 100644 index 0000000..6ed77e5 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py @@ -0,0 +1,85 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...models.errors_code import ErrorsCode +from ...types import Response + + +def _get_kwargs_leaveChat( + self, + id: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "delete", + "url": f"/chats/{id}/leave", + } + + return _kwargs + + +def _parse_response_leaveChat(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + + response_404.append(response_404_item) + + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_leaveChat(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_leaveChat(response=response), + ) + + +async def leaveChat( + self, + id: int, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + kwargs = self._get_kwargs_leaveChat( + id=id, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_leaveChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py new file mode 100644 index 0000000..5710447 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -0,0 +1,89 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...models.errors_code import ErrorsCode +from ...models.post_members_to_chats_body import PostMembersToChatsBody +from ...types import Response + + +def _get_kwargs_postMembersToChats( + self, + id: int, + body: PostMembersToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/members", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_postMembersToChats(response=response), + ) + + +async def postMembersToChats( + self, + id: int, + body: PostMembersToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + kwargs = self._get_kwargs_postMembersToChats( + id=id, + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_postMembersToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py new file mode 100644 index 0000000..1d90b2c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -0,0 +1,89 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...models.errors_code import ErrorsCode +from ...models.post_tags_to_chats_body import PostTagsToChatsBody +from ...types import Response + + +def _get_kwargs_postTagsToChats( + self, + id: int, + body: PostTagsToChatsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": f"/chats/{id}/group_tags", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + + response_400.append(response_400_item) + + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=self._parse_response_postTagsToChats(response=response), + ) + + +async def postTagsToChats( + self, + id: int, + body: PostTagsToChatsBody, +) -> Optional[Union[Any, list["ErrorsCode"]]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + + kwargs = self._get_kwargs_postTagsToChats( + id=id, + body=body, + ) + + response = await self.client.get_async_httpx_client().request(**kwargs) + + return self._build_response_postTagsToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py new file mode 100644 index 0000000..f6cbb07 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py @@ -0,0 +1,1223 @@ +from .models import ( + BadRequest, + CreateChatBody, + CreateChatResponse201, + CreateChatResponse400, + CreateChatResponse404, + CreateChatResponse422, + CreateMessageBody, + CreateMessageResponse201, + CreateTaskBody, + CreateTaskResponse201, + CreateTaskResponse400, + CreateThreadResponse200, + DeleteMessageReactionsResponse400, + DeleteMessageReactionsResponse404, + DirectResponse, + EditMessageBody, + EditMessageResponse200, + Error, + ErrorsCode, + FileResponse, + GetChatResponse200, + GetChatResponse404, + GetChatsAvailability, + GetChatsResponse200, + GetChatsResponse400, + GetChatsResponse404, + GetChatsResponse422, + GetChatsSortid, + GetCommonMethodsResponse200, + GetEmployeeResponse200, + GetEmployeesResponse200, + GetListMessageResponse200, + GetMessageReactionsBody, + GetMessageReactionsResponse200, + GetMessageResponse200, + GetStatusResponse200, + GetTagResponse200, + GetTagResponse404, + GetTagsEmployeesResponse200, + GetTagsResponse200, + GetTagsResponse400, + NotFound, + PostMembersToChatsBody, + PostMessageReactionsBody, + PostMessageReactionsResponse400, + PostMessageReactionsResponse403, + PostMessageReactionsResponse404, + PostTagsToChatsBody, + PutStatusResponse201, + QueryStatus +) + +from typing import ( + Any, + Optional, + Union, + cast +) + +from .types import ( + Response, + UNSET, + Unset +) + +from . import errors +from http import HTTPStatus + +import datetime + +import httpx +from ...client_servis import AuthenticatedClient + +class Pachca: + """Главный класс библиотеки.""" + + def __init__(self, token): + self.client = AuthenticatedClient(token=token) + + + + def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + if response.status_code == 201: + response_201 = CreateChatResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = CreateChatResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = CreateChatResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = CreateChatResponse422.from_dict(response.json()) + return response_422 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) + + async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: + """ Новая беседа или канал + + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\\ + + Args: + body (CreateChatBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] + """ + kwargs = self._get_kwargs_createChat(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createChat(response=response).parsed + + def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} + return _kwargs + + def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + if response.status_code == 200: + response_200 = GetChatResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = GetChatResponse404.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) + + async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: + """Информация о беседе или канале + + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatResponse200, GetChatResponse404] + """ + kwargs = self._get_kwargs_getChat(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChat(response=response).parsed + + def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + json_sortid: Union[Unset, str] = UNSET + if not isinstance(sortid, Unset): + json_sortid = sortid.value + params['sort[id]'] = json_sortid + params['per'] = per + params['page'] = page + json_availability: Union[Unset, str] = UNSET + if not isinstance(availability, Unset): + json_availability = availability.value + params['availability'] = json_availability + json_last_message_at_after: Union[Unset, str] = UNSET + if not isinstance(last_message_at_after, Unset): + json_last_message_at_after = last_message_at_after.isoformat() + params['last_message_at_after'] = json_last_message_at_after + json_last_message_at_before: Union[Unset, str] = UNSET + if not isinstance(last_message_at_before, Unset): + json_last_message_at_before = last_message_at_before.isoformat() + params['last_message_at_before'] = json_last_message_at_before + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} + return _kwargs + + def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + if response.status_code == 200: + response_200 = GetChatsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = GetChatsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = GetChatsResponse404.from_dict(response.json()) + return response_404 + if response.status_code == 422: + response_422 = GetChatsResponse422.from_dict(response.json()) + return response_422 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) + + async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: + """Список бесед и каналов + + Получения списка бесед и каналов по заданным параметрам. + + Args: + sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + availability (Union[Unset, GetChatsAvailability]): Default: + GetChatsAvailability.IS_MEMBER. + last_message_at_after (Union[Unset, datetime.datetime]): + last_message_at_before (Union[Unset, datetime.datetime]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] + """ + kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getChats(response=response).parsed + + def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} + return _kwargs + + def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + if response.status_code == 200: + response_200 = CreateThreadResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) + + async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: + """Создание нового треда + + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в + ответе вернётся информация об уже созданном ранее треде. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateThreadResponse200, NotFound] + """ + kwargs = self._get_kwargs_createThread(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createThread(response=response).parsed + + def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['entity_type'] = entity_type + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} + return _kwargs + + def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + if response.status_code == 200: + response_200 = GetCommonMethodsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) + + async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: + """Список дополнительных полей + + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей + компании. + + Args: + entity_type (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetCommonMethodsResponse200] + """ + kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getCommonMethods(response=response).parsed + + def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} + _body = body.to_multipart() + _kwargs['files'] = _body + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) + + def _get_kwargs_getUploads(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} + return _kwargs + + def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: + if response.status_code == 200: + response_200 = FileResponse.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) + + async def getUploads(self) -> Optional[FileResponse]: + """Получение подписи и ключа для загрузки файла + + Возвращает параметры, необходимые для безопасной загрузки файла. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + FileResponse + """ + kwargs = self._get_kwargs_getUploads() + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getUploads(response=response).parsed + + def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} + return _kwargs + + def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetEmployeeResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) + + async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetEmployeeResponse200, NotFound] + """ + kwargs = self._get_kwargs_getEmployee(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployee(response=response).parsed + + def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params['query'] = query + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} + return _kwargs + + def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: + if response.status_code == 200: + response_200 = GetEmployeesResponse200.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) + + async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: + """получение актуального списка всех сотрудников компании + + Fetch a paginated list of employees with optional filtering by query. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + query (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetEmployeesResponse200 + """ + kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getEmployees(response=response).parsed + + def _get_kwargs_editMessage(self, id: int, body: EditMessageBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_editMessage(self, response: httpx.Response) -> Optional[Union[EditMessageResponse200, list['ErrorsCode']]]: + if response.status_code == 200: + response_200 = EditMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_editMessage(self, response: httpx.Response) -> Response[Union[EditMessageResponse200, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_editMessage(response=response)) + + async def editMessage(self, id: int, body: EditMessageBody) -> Optional[Union[EditMessageResponse200, list['ErrorsCode']]]: + """Редактирование сообщения + + Метод для редактирования сообщения или комментария. + + Args: + id (int): + body (EditMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[EditMessageResponse200, list['ErrorsCode']] + """ + kwargs = self._get_kwargs_editMessage(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_editMessage(response=response).parsed + + def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + if response.status_code == 201: + response_201 = CreateMessageResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for componentsschemas_errors_item_data in _response_404: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + response_404.append(componentsschemas_errors_item) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) + + async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: + """создание нового сообщения + + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + + Args: + body (CreateMessageBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, CreateMessageResponse201, list['Error']] + """ + kwargs = self._get_kwargs_createMessage(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createMessage(response=response).parsed + + def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['chat_id'] = chat_id + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} + return _kwargs + + def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetListMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) + + async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + + Args: + chat_id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetListMessageResponse200, NotFound] + """ + kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getListMessage(response=response).parsed + + def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} + return _kwargs + + def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) + + async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: + """получение информации о сообщении + + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetMessageResponse200, NotFound] + """ + kwargs = self._get_kwargs_getMessage(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getMessage(response=response).parsed + + def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: + params: dict[str, Any] = {} + params['code'] = code + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} + return _kwargs + + def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 404: + response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) + + async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: + """Удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены + авторизованным пользователем. + + Args: + id (int): + code (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] + """ + kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_deleteMessageReactions(response=response).parsed + + def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + if response.status_code == 200: + response_200 = GetMessageReactionsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = NotFound.from_dict(response.json()) + return response_404 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) + + async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: + """Получение актуального списка реакций. + + Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное + сообщение. + + Args: + id (int): + body (GetMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetMessageReactionsResponse200, NotFound] + """ + kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getMessageReactions(response=response).parsed + + def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + if response.status_code == 400: + response_400 = PostMessageReactionsResponse400.from_dict(response.json()) + return response_400 + if response.status_code == 403: + response_403 = PostMessageReactionsResponse403.from_dict(response.json()) + return response_403 + if response.status_code == 404: + response_404 = PostMessageReactionsResponse404.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) + + async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: + """Добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может + установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 + уникальных реакций. - Сообщение может иметь не более 1000 реакций. + + Args: + id (int): + body (PostMessageReactionsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] + """ + kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postMessageReactions(response=response).parsed + + def _get_kwargs_createTask(self, body: CreateTaskBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_createTask(self, response: httpx.Response) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: + if response.status_code == 201: + response_201 = CreateTaskResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = CreateTaskResponse400.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_createTask(self, response: httpx.Response) -> Response[Union[CreateTaskResponse201, CreateTaskResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createTask(response=response)) + + async def createTask(self, body: CreateTaskBody) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: + """Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, + простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим + текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + + Args: + body (CreateTaskBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[CreateTaskResponse201, CreateTaskResponse400] + """ + kwargs = self._get_kwargs_createTask(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_createTask(response=response).parsed + + def _get_kwargs_delStatus(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} + return _kwargs + + def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: + return None + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) + + def _get_kwargs_getStatus(self) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} + return _kwargs + + def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: + if response.status_code == 200: + response_200 = GetStatusResponse200.from_dict(response.json()) + return response_200 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) + + async def getStatus(self) -> Optional[GetStatusResponse200]: + """получение информации о своем статусе + + Параметры запроса отсутствуют + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + GetStatusResponse200 + """ + kwargs = self._get_kwargs_getStatus() + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getStatus(response=response).parsed + + def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: + if response.status_code == 201: + response_201 = PutStatusResponse201.from_dict(response.json()) + return response_201 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) + + async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: + """новый статус + + Создание нового статуса. + + Args: + body (QueryStatus): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, PutStatusResponse201] + """ + kwargs = self._get_kwargs_putStatus(body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_putStatus(response=response).parsed + + def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} + return _kwargs + + def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + if response.status_code == 200: + response_200 = GetTagResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 404: + response_404 = GetTagResponse404.from_dict(response.json()) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) + + async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: + """Информация о теге + + Параметры запроса отсутствуют + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagResponse200, GetTagResponse404] + """ + kwargs = self._get_kwargs_getTag(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTag(response=response).parsed + + def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} + return _kwargs + + def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + if response.status_code == 200: + response_200 = GetTagsResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = GetTagsResponse400.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) + + async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: + """Список тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. + + Args: + per (Union[Unset, int]): Default: 50. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[GetTagsResponse200, GetTagsResponse400] + """ + kwargs = self._get_kwargs_getTags(per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTags(response=response).parsed + + def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: + params: dict[str, Any] = {} + params['per'] = per + params['page'] = page + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} + return _kwargs + + def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + if response.status_code == 200: + response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) + return response_200 + if response.status_code == 400: + response_400 = BadRequest.from_dict(response.json()) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) + + async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. + + Args: + id (int): + per (Union[Unset, int]): Default: 25. + page (Union[Unset, int]): Default: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[BadRequest, GetTagsEmployeesResponse200] + """ + kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_getTagsEmployees(response=response).parsed + + def _get_kwargs_leaveChat(self, id: int) -> dict[str, Any]: + _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} + return _kwargs + + def _parse_response_leaveChat(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 200: + response_200 = cast(Any, None) + return response_200 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if response.status_code == 404: + response_404 = [] + _response_404 = response.json() + for response_404_item_data in _response_404: + response_404_item = ErrorsCode.from_dict(response_404_item_data) + response_404.append(response_404_item) + return response_404 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_leaveChat(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_leaveChat(response=response)) + + async def leaveChat(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: + """Выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. + + Args: + id (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + kwargs = self._get_kwargs_leaveChat(id=id) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_leaveChat(response=response).parsed + + def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) + + async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostMembersToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postMembersToChats(response=response).parsed + + def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: + headers: dict[str, Any] = {} + _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} + _body = body.to_dict() + _kwargs['json'] = _body + headers['Content-Type'] = 'application/json' + _kwargs['headers'] = headers + return _kwargs + + def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: + if response.status_code == 201: + response_201 = cast(Any, None) + return response_201 + if response.status_code == 400: + response_400 = [] + _response_400 = response.json() + for response_400_item_data in _response_400: + response_400_item = ErrorsCode.from_dict(response_400_item_data) + response_400.append(response_400_item) + return response_400 + if self.client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: + return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) + + async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + + Args: + id (int): Example: 533. + body (PostTagsToChatsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['ErrorsCode']] + """ + kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) + response = await self.client.get_async_httpx_client().request(**kwargs) + return self._build_response_postTagsToChats(response=response).parsed + + + \ No newline at end of file diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py new file mode 100644 index 0000000..5f92e76 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py @@ -0,0 +1,16 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py new file mode 100644 index 0000000..6138024 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py @@ -0,0 +1,189 @@ +"""Contains all the data models used in inputs/outputs""" + +from .bad_request import BadRequest +from .base_employee import BaseEmployee +from .base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem +from .button import Button +from .chat import Chat +from .create_chat_body import CreateChatBody +from .create_chat_response_201 import CreateChatResponse201 +from .create_chat_response_400 import CreateChatResponse400 +from .create_chat_response_404 import CreateChatResponse404 +from .create_chat_response_422 import CreateChatResponse422 +from .create_message import CreateMessage +from .create_message_body import CreateMessageBody +from .create_message_entity_type import CreateMessageEntityType +from .create_message_files_item import CreateMessageFilesItem +from .create_message_files_item_file_type import CreateMessageFilesItemFileType +from .create_message_response_201 import CreateMessageResponse201 +from .create_task_body import CreateTaskBody +from .create_task_body_task import CreateTaskBodyTask +from .create_task_body_task_custom_properties_item import CreateTaskBodyTaskCustomPropertiesItem +from .create_task_response_201 import CreateTaskResponse201 +from .create_task_response_201_data import CreateTaskResponse201Data +from .create_task_response_201_data_custom_properties_item import CreateTaskResponse201DataCustomPropertiesItem +from .create_task_response_400 import CreateTaskResponse400 +from .create_thread_response_200 import CreateThreadResponse200 +from .create_thread_response_200_data import CreateThreadResponse200Data +from .delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 +from .delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem +from .delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, +) +from .delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 +from .delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem +from .delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, +) +from .direct_response import DirectResponse +from .edit_message_body import EditMessageBody +from .edit_message_response_200 import EditMessageResponse200 +from .edit_messages import EditMessages +from .edit_messages_buttons_item_item import EditMessagesButtonsItemItem +from .edit_messages_files import EditMessagesFiles +from .edit_messages_files_file_type import EditMessagesFilesFileType +from .employee import Employee +from .error import Error +from .error_payload import ErrorPayload +from .errors_code import ErrorsCode +from .errors_code_payload import ErrorsCodePayload +from .file_response import FileResponse +from .get_chat_response_200 import GetChatResponse200 +from .get_chat_response_404 import GetChatResponse404 +from .get_chats_availability import GetChatsAvailability +from .get_chats_response_200 import GetChatsResponse200 +from .get_chats_response_400 import GetChatsResponse400 +from .get_chats_response_404 import GetChatsResponse404 +from .get_chats_response_422 import GetChatsResponse422 +from .get_chats_sortid import GetChatsSortid +from .get_common_methods_response_200 import GetCommonMethodsResponse200 +from .get_employee_response_200 import GetEmployeeResponse200 +from .get_employees_response_200 import GetEmployeesResponse200 +from .get_list_message_response_200 import GetListMessageResponse200 +from .get_message_reactions_body import GetMessageReactionsBody +from .get_message_reactions_response_200 import GetMessageReactionsResponse200 +from .get_message_response_200 import GetMessageResponse200 +from .get_status_response_200 import GetStatusResponse200 +from .get_tag_response_200 import GetTagResponse200 +from .get_tag_response_404 import GetTagResponse404 +from .get_tag_response_404_errors_item import GetTagResponse404ErrorsItem +from .get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload +from .get_tags_employees_response_200 import GetTagsEmployeesResponse200 +from .get_tags_response_200 import GetTagsResponse200 +from .get_tags_response_400 import GetTagsResponse400 +from .get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem +from .get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload +from .message import Message +from .message_entity_type import MessageEntityType +from .message_files_item import MessageFilesItem +from .message_files_item_file_type import MessageFilesItemFileType +from .message_forwarding import MessageForwarding +from .message_thread import MessageThread +from .not_found import NotFound +from .post_members_to_chats_body import PostMembersToChatsBody +from .post_message_reactions_body import PostMessageReactionsBody +from .post_message_reactions_response_400 import PostMessageReactionsResponse400 +from .post_message_reactions_response_403 import PostMessageReactionsResponse403 +from .post_message_reactions_response_404 import PostMessageReactionsResponse404 +from .post_tags_to_chats_body import PostTagsToChatsBody +from .put_status_response_201 import PutStatusResponse201 +from .query_chat import QueryChat +from .query_common_methods import QueryCommonMethods +from .query_status import QueryStatus +from .query_status_status import QueryStatusStatus +from .reaction import Reaction +from .status_type_0 import StatusType0 +from .tag import Tag + +__all__ = ( + "BadRequest", + "BaseEmployee", + "BaseEmployeeCustomPropertiesItem", + "Button", + "Chat", + "CreateChatBody", + "CreateChatResponse201", + "CreateChatResponse400", + "CreateChatResponse404", + "CreateChatResponse422", + "CreateMessage", + "CreateMessageBody", + "CreateMessageEntityType", + "CreateMessageFilesItem", + "CreateMessageFilesItemFileType", + "CreateMessageResponse201", + "CreateTaskBody", + "CreateTaskBodyTask", + "CreateTaskBodyTaskCustomPropertiesItem", + "CreateTaskResponse201", + "CreateTaskResponse201Data", + "CreateTaskResponse201DataCustomPropertiesItem", + "CreateTaskResponse400", + "CreateThreadResponse200", + "CreateThreadResponse200Data", + "DeleteMessageReactionsResponse400", + "DeleteMessageReactionsResponse400ErrorsItem", + "DeleteMessageReactionsResponse400ErrorsItemPayload", + "DeleteMessageReactionsResponse404", + "DeleteMessageReactionsResponse404ErrorsItem", + "DeleteMessageReactionsResponse404ErrorsItemPayload", + "DirectResponse", + "EditMessageBody", + "EditMessageResponse200", + "EditMessages", + "EditMessagesButtonsItemItem", + "EditMessagesFiles", + "EditMessagesFilesFileType", + "Employee", + "Error", + "ErrorPayload", + "ErrorsCode", + "ErrorsCodePayload", + "FileResponse", + "GetChatResponse200", + "GetChatResponse404", + "GetChatsAvailability", + "GetChatsResponse200", + "GetChatsResponse400", + "GetChatsResponse404", + "GetChatsResponse422", + "GetChatsSortid", + "GetCommonMethodsResponse200", + "GetEmployeeResponse200", + "GetEmployeesResponse200", + "GetListMessageResponse200", + "GetMessageReactionsBody", + "GetMessageReactionsResponse200", + "GetMessageResponse200", + "GetStatusResponse200", + "GetTagResponse200", + "GetTagResponse404", + "GetTagResponse404ErrorsItem", + "GetTagResponse404ErrorsItemPayload", + "GetTagsEmployeesResponse200", + "GetTagsResponse200", + "GetTagsResponse400", + "GetTagsResponse400ErrorsItem", + "GetTagsResponse400ErrorsItemPayload", + "Message", + "MessageEntityType", + "MessageFilesItem", + "MessageFilesItemFileType", + "MessageForwarding", + "MessageThread", + "NotFound", + "PostMembersToChatsBody", + "PostMessageReactionsBody", + "PostMessageReactionsResponse400", + "PostMessageReactionsResponse403", + "PostMessageReactionsResponse404", + "PostTagsToChatsBody", + "PutStatusResponse201", + "QueryChat", + "QueryCommonMethods", + "QueryStatus", + "QueryStatusStatus", + "Reaction", + "StatusType0", + "Tag", +) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py new file mode 100644 index 0000000..17dd6ed --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BadRequest") + + +@_attrs_define +class BadRequest: + """ + Attributes: + error (Union[Unset, str]): + message (Union[Unset, str]): + """ + + error: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + message = d.pop("message", UNSET) + + bad_request = cls( + error=error, + message=message, + ) + + bad_request.additional_properties = d + return bad_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py new file mode 100644 index 0000000..b6a0314 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py @@ -0,0 +1,186 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + +T = TypeVar("T", bound="BaseEmployee") + + +@_attrs_define +class BaseEmployee: + """Базовый класс сотрудника. + + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + base_employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + ) + + base_employee.additional_properties = d + return base_employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py new file mode 100644 index 0000000..bee25c8 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="BaseEmployeeCustomPropertiesItem") + + +@_attrs_define +class BaseEmployeeCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + base_employee_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + base_employee_custom_properties_item.additional_properties = d + return base_employee_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py new file mode 100644 index 0000000..64ea323 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py @@ -0,0 +1,78 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Button") + + +@_attrs_define +class Button: + """ + Attributes: + text (str): + url (Union[Unset, str]): + data (Union[Unset, str]): + """ + + text: str + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + } + ) + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text") + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + button = cls( + text=text, + url=url, + data=data, + ) + + button.additional_properties = d + return button + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py new file mode 100644 index 0000000..7ef2560 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py @@ -0,0 +1,162 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Chat") + + +@_attrs_define +class Chat: + """Беседа или канал + + Attributes: + id (Union[Unset, int]): Идентификатор беседы или канала Example: 334. + name (Union[Unset, str]): Название Example: 🤿 aqua. + owner_id (Union[Unset, int]): Идентификатор пользователя, создавшего беседу или канал Example: 185. + created_at (Union[Unset, datetime.datetime]): Дата и время создания беседы или канала (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:56:53.000Z. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, участников Example: [185, 186, 187]. + group_tag_ids (Union[Unset, list[int]]): Массив идентификаторов тегов, участников + channel (Union[Unset, bool]): Тип: беседа (false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (false) или открытый (true) + last_message_at (Union[Unset, datetime.datetime]): Дата и время создания последнего сообщения в беседе/канале + (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:58:13.000Z. + meet_room_url (Union[Unset, str]): Ссылка на Видеочат Example: https://meet.pachca.com/aqua-94bb21b5. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + owner_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + member_ids: Union[Unset, list[int]] = UNSET + group_tag_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + last_message_at: Union[Unset, datetime.datetime] = UNSET + meet_room_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + owner_id = self.owner_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + group_tag_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.group_tag_ids, Unset): + group_tag_ids = self.group_tag_ids + + channel = self.channel + + public = self.public + + last_message_at: Union[Unset, str] = UNSET + if not isinstance(self.last_message_at, Unset): + last_message_at = self.last_message_at.isoformat() + + meet_room_url = self.meet_room_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if owner_id is not UNSET: + field_dict["owner_id"] = owner_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if group_tag_ids is not UNSET: + field_dict["group_tag_ids"] = group_tag_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + if last_message_at is not UNSET: + field_dict["last_message_at"] = last_message_at + if meet_room_url is not UNSET: + field_dict["meet_room_url"] = meet_room_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + owner_id = d.pop("owner_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + group_tag_ids = cast(list[int], d.pop("group_tag_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + _last_message_at = d.pop("last_message_at", UNSET) + last_message_at: Union[Unset, datetime.datetime] + if isinstance(_last_message_at, Unset): + last_message_at = UNSET + else: + last_message_at = isoparse(_last_message_at) + + meet_room_url = d.pop("meet_room_url", UNSET) + + chat = cls( + id=id, + name=name, + owner_id=owner_id, + created_at=created_at, + member_ids=member_ids, + group_tag_ids=group_tag_ids, + channel=channel, + public=public, + last_message_at=last_message_at, + meet_room_url=meet_room_url, + ) + + chat.additional_properties = d + return chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py new file mode 100644 index 0000000..8b9e361 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_chat import QueryChat + + +T = TypeVar("T", bound="CreateChatBody") + + +@_attrs_define +class CreateChatBody: + """ + Attributes: + chat (Union[Unset, QueryChat]): Собранный объект параметров создаваемой беседы или канала + """ + + chat: Union[Unset, "QueryChat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + chat: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.chat, Unset): + chat = self.chat.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if chat is not UNSET: + field_dict["chat"] = chat + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_chat import QueryChat + + d = src_dict.copy() + _chat = d.pop("chat", UNSET) + chat: Union[Unset, QueryChat] + if isinstance(_chat, Unset): + chat = UNSET + else: + chat = QueryChat.from_dict(_chat) + + create_chat_body = cls( + chat=chat, + ) + + create_chat_body.additional_properties = d + return create_chat_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py new file mode 100644 index 0000000..3a928ef --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="CreateChatResponse201") + + +@_attrs_define +class CreateChatResponse201: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + create_chat_response_201 = cls( + data=data, + ) + + create_chat_response_201.additional_properties = d + return create_chat_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py new file mode 100644 index 0000000..1d7fd30 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse400") + + +@_attrs_define +class CreateChatResponse400: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_400 = cls( + errors=errors, + ) + + create_chat_response_400.additional_properties = d + return create_chat_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py new file mode 100644 index 0000000..3de2654 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse404") + + +@_attrs_define +class CreateChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_404 = cls( + errors=errors, + ) + + create_chat_response_404.additional_properties = d + return create_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py new file mode 100644 index 0000000..c917758 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="CreateChatResponse422") + + +@_attrs_define +class CreateChatResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + create_chat_response_422 = cls( + errors=errors, + ) + + create_chat_response_422.additional_properties = d + return create_chat_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py new file mode 100644 index 0000000..63e52de --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py @@ -0,0 +1,178 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_entity_type import CreateMessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + +T = TypeVar("T", bound="CreateMessage") + + +@_attrs_define +class CreateMessage: + """ + Attributes: + entity_id (int): + content (str): + entity_type (Union[Unset, CreateMessageEntityType]): Default: CreateMessageEntityType.DISCUSSION. + files (Union[Unset, list['CreateMessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + parent_message_id (Union[None, Unset, int]): + skip_invite_mentions (Union[Unset, bool]): Default: False. + link_preview (Union[Unset, bool]): Default: False. + """ + + entity_id: int + content: str + entity_type: Union[Unset, CreateMessageEntityType] = CreateMessageEntityType.DISCUSSION + files: Union[Unset, list["CreateMessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + skip_invite_mentions: Union[Unset, bool] = False + link_preview: Union[Unset, bool] = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_id = self.entity_id + + content = self.content + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + skip_invite_mentions = self.skip_invite_mentions + + link_preview = self.link_preview + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entity_id": entity_id, + "content": content, + } + ) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + if skip_invite_mentions is not UNSET: + field_dict["skip_invite_mentions"] = skip_invite_mentions + if link_preview is not UNSET: + field_dict["link_preview"] = link_preview + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.create_message_files_item import CreateMessageFilesItem + + d = src_dict.copy() + entity_id = d.pop("entity_id") + + content = d.pop("content") + + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, CreateMessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = CreateMessageEntityType(_entity_type) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = CreateMessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + skip_invite_mentions = d.pop("skip_invite_mentions", UNSET) + + link_preview = d.pop("link_preview", UNSET) + + create_message = cls( + entity_id=entity_id, + content=content, + entity_type=entity_type, + files=files, + buttons=buttons, + parent_message_id=parent_message_id, + skip_invite_mentions=skip_invite_mentions, + link_preview=link_preview, + ) + + create_message.additional_properties = d + return create_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py new file mode 100644 index 0000000..a8960fe --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_message import CreateMessage + + +T = TypeVar("T", bound="CreateMessageBody") + + +@_attrs_define +class CreateMessageBody: + """ + Attributes: + message (Union[Unset, CreateMessage]): + """ + + message: Union[Unset, "CreateMessage"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_message import CreateMessage + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, CreateMessage] + if isinstance(_message, Unset): + message = UNSET + else: + message = CreateMessage.from_dict(_message) + + create_message_body = cls( + message=message, + ) + + create_message_body.additional_properties = d + return create_message_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py new file mode 100644 index 0000000..067c6f4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class CreateMessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py new file mode 100644 index 0000000..a7c8ee3 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py @@ -0,0 +1,84 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_message_files_item_file_type import CreateMessageFilesItemFileType + +T = TypeVar("T", bound="CreateMessageFilesItem") + + +@_attrs_define +class CreateMessageFilesItem: + """ + Attributes: + key (str): + name (str): + file_type (CreateMessageFilesItemFileType): + size (int): + """ + + key: str + name: str + file_type: CreateMessageFilesItemFileType + size: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "key": key, + "name": name, + "file_type": file_type, + "size": size, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key") + + name = d.pop("name") + + file_type = CreateMessageFilesItemFileType(d.pop("file_type")) + + size = d.pop("size") + + create_message_files_item = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + create_message_files_item.additional_properties = d + return create_message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py new file mode 100644 index 0000000..89889f9 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CreateMessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py new file mode 100644 index 0000000..b016d4c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="CreateMessageResponse201") + + +@_attrs_define +class CreateMessageResponse201: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + create_message_response_201 = cls( + data=data, + ) + + create_message_response_201.additional_properties = d + return create_message_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py new file mode 100644 index 0000000..c99dbf2 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_task_body_task import CreateTaskBodyTask + + +T = TypeVar("T", bound="CreateTaskBody") + + +@_attrs_define +class CreateTaskBody: + """ + Attributes: + task (Union[Unset, CreateTaskBodyTask]): + """ + + task: Union[Unset, "CreateTaskBodyTask"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + task: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.task, Unset): + task = self.task.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if task is not UNSET: + field_dict["task"] = task + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_task_body_task import CreateTaskBodyTask + + d = src_dict.copy() + _task = d.pop("task", UNSET) + task: Union[Unset, CreateTaskBodyTask] + if isinstance(_task, Unset): + task = UNSET + else: + task = CreateTaskBodyTask.from_dict(_task) + + create_task_body = cls( + task=task, + ) + + create_task_body.additional_properties = d + return create_task_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py new file mode 100644 index 0000000..f441ba6 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py @@ -0,0 +1,123 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_task_body_task_custom_properties_item import CreateTaskBodyTaskCustomPropertiesItem + + +T = TypeVar("T", bound="CreateTaskBodyTask") + + +@_attrs_define +class CreateTaskBodyTask: + """ + Attributes: + kind (str): Тип напоминания (call, meeting, reminder, event, email) + content (str): Описание напоминания + due_at (datetime.datetime): Срок выполнения напоминания (ISO-8601) + priority (Union[Unset, int]): Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей + custom_properties (Union[Unset, list['CreateTaskBodyTaskCustomPropertiesItem']]): + """ + + kind: str + content: str + due_at: datetime.datetime + priority: Union[Unset, int] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["CreateTaskBodyTaskCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind = self.kind + + content = self.content + + due_at = self.due_at.isoformat() + + priority = self.priority + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "content": content, + "due_at": due_at, + } + ) + if priority is not UNSET: + field_dict["priority"] = priority + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_task_body_task_custom_properties_item import CreateTaskBodyTaskCustomPropertiesItem + + d = src_dict.copy() + kind = d.pop("kind") + + content = d.pop("content") + + due_at = isoparse(d.pop("due_at")) + + priority = d.pop("priority", UNSET) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = CreateTaskBodyTaskCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + create_task_body_task = cls( + kind=kind, + content=content, + due_at=due_at, + priority=priority, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + create_task_body_task.additional_properties = d + return create_task_body_task + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py new file mode 100644 index 0000000..7e4a42d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateTaskBodyTaskCustomPropertiesItem") + + +@_attrs_define +class CreateTaskBodyTaskCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + value (Union[Unset, str]): Значение поля + """ + + id: Union[Unset, int] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + value = d.pop("value", UNSET) + + create_task_body_task_custom_properties_item = cls( + id=id, + value=value, + ) + + create_task_body_task_custom_properties_item.additional_properties = d + return create_task_body_task_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py new file mode 100644 index 0000000..f34110e --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_task_response_201_data import CreateTaskResponse201Data + + +T = TypeVar("T", bound="CreateTaskResponse201") + + +@_attrs_define +class CreateTaskResponse201: + """ + Attributes: + data (Union[Unset, CreateTaskResponse201Data]): + """ + + data: Union[Unset, "CreateTaskResponse201Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_task_response_201_data import CreateTaskResponse201Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, CreateTaskResponse201Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = CreateTaskResponse201Data.from_dict(_data) + + create_task_response_201 = cls( + data=data, + ) + + create_task_response_201.additional_properties = d + return create_task_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py new file mode 100644 index 0000000..f9179d1 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py @@ -0,0 +1,179 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_task_response_201_data_custom_properties_item import ( + CreateTaskResponse201DataCustomPropertiesItem, + ) + + +T = TypeVar("T", bound="CreateTaskResponse201Data") + + +@_attrs_define +class CreateTaskResponse201Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного напоминания + kind (Union[Unset, str]): Тип + content (Union[Unset, str]): Описание + due_at (Union[Unset, datetime.datetime]): Срок выполнения (ISO-8601) + priority (Union[Unset, int]): Приоритет + user_id (Union[Unset, int]): Идентификатор пользователя-создателя + status (Union[Unset, str]): Статус напоминания + created_at (Union[Unset, datetime.datetime]): Дата и время создания + performer_ids (Union[Unset, list[int]]): + custom_properties (Union[Unset, list['CreateTaskResponse201DataCustomPropertiesItem']]): + """ + + id: Union[Unset, int] = UNSET + kind: Union[Unset, str] = UNSET + content: Union[Unset, str] = UNSET + due_at: Union[Unset, datetime.datetime] = UNSET + priority: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + status: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + performer_ids: Union[Unset, list[int]] = UNSET + custom_properties: Union[Unset, list["CreateTaskResponse201DataCustomPropertiesItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + kind = self.kind + + content = self.content + + due_at: Union[Unset, str] = UNSET + if not isinstance(self.due_at, Unset): + due_at = self.due_at.isoformat() + + priority = self.priority + + user_id = self.user_id + + status = self.status + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + performer_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.performer_ids, Unset): + performer_ids = self.performer_ids + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if kind is not UNSET: + field_dict["kind"] = kind + if content is not UNSET: + field_dict["content"] = content + if due_at is not UNSET: + field_dict["due_at"] = due_at + if priority is not UNSET: + field_dict["priority"] = priority + if user_id is not UNSET: + field_dict["user_id"] = user_id + if status is not UNSET: + field_dict["status"] = status + if created_at is not UNSET: + field_dict["created_at"] = created_at + if performer_ids is not UNSET: + field_dict["performer_ids"] = performer_ids + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_task_response_201_data_custom_properties_item import ( + CreateTaskResponse201DataCustomPropertiesItem, + ) + + d = src_dict.copy() + id = d.pop("id", UNSET) + + kind = d.pop("kind", UNSET) + + content = d.pop("content", UNSET) + + _due_at = d.pop("due_at", UNSET) + due_at: Union[Unset, datetime.datetime] + if isinstance(_due_at, Unset): + due_at = UNSET + else: + due_at = isoparse(_due_at) + + priority = d.pop("priority", UNSET) + + user_id = d.pop("user_id", UNSET) + + status = d.pop("status", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = CreateTaskResponse201DataCustomPropertiesItem.from_dict( + custom_properties_item_data + ) + + custom_properties.append(custom_properties_item) + + create_task_response_201_data = cls( + id=id, + kind=kind, + content=content, + due_at=due_at, + priority=priority, + user_id=user_id, + status=status, + created_at=created_at, + performer_ids=performer_ids, + custom_properties=custom_properties, + ) + + create_task_response_201_data.additional_properties = d + return create_task_response_201_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py new file mode 100644 index 0000000..05e003e --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py @@ -0,0 +1,85 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateTaskResponse201DataCustomPropertiesItem") + + +@_attrs_define +class CreateTaskResponse201DataCustomPropertiesItem: + """ + Attributes: + id (Union[Unset, int]): Идентификатор поля + name (Union[Unset, str]): Название поля + data_type (Union[Unset, str]): Тип поля (string, number, date или link) + value (Union[Unset, str]): Значение + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + value = d.pop("value", UNSET) + + create_task_response_201_data_custom_properties_item = cls( + id=id, + name=name, + data_type=data_type, + value=value, + ) + + create_task_response_201_data_custom_properties_item.additional_properties = d + return create_task_response_201_data_custom_properties_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py new file mode 100644 index 0000000..ae66b97 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateTaskResponse400") + + +@_attrs_define +class CreateTaskResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + create_task_response_400 = cls( + error=error, + ) + + create_task_response_400.additional_properties = d + return create_task_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py new file mode 100644 index 0000000..15fd0b4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + +T = TypeVar("T", bound="CreateThreadResponse200") + + +@_attrs_define +class CreateThreadResponse200: + """ + Attributes: + data (Union[Unset, CreateThreadResponse200Data]): + """ + + data: Union[Unset, "CreateThreadResponse200Data"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.create_thread_response_200_data import CreateThreadResponse200Data + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, CreateThreadResponse200Data] + if isinstance(_data, Unset): + data = UNSET + else: + data = CreateThreadResponse200Data.from_dict(_data) + + create_thread_response_200 = cls( + data=data, + ) + + create_thread_response_200.additional_properties = d + return create_thread_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py new file mode 100644 index 0000000..93b7457 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py @@ -0,0 +1,104 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CreateThreadResponse200Data") + + +@_attrs_define +class CreateThreadResponse200Data: + """ + Attributes: + id (Union[Unset, int]): Идентификатор созданного треда. + chat_id (Union[Unset, int]): Идентификатор чата треда. + message_id (Union[Unset, int]): Идентификатор сообщения, к которому был создан тред. + message_chat_id (Union[Unset, int]): Идентификатор чата сообщения. + updated_at (Union[Unset, datetime.datetime]): Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + message_id: Union[Unset, int] = UNSET + message_chat_id: Union[Unset, int] = UNSET + updated_at: Union[Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + message_id = self.message_id + + message_chat_id = self.message_chat_id + + updated_at: Union[Unset, str] = UNSET + if not isinstance(self.updated_at, Unset): + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if message_id is not UNSET: + field_dict["message_id"] = message_id + if message_chat_id is not UNSET: + field_dict["message_chat_id"] = message_chat_id + if updated_at is not UNSET: + field_dict["updated_at"] = updated_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_id = d.pop("message_id", UNSET) + + message_chat_id = d.pop("message_chat_id", UNSET) + + _updated_at = d.pop("updated_at", UNSET) + updated_at: Union[Unset, datetime.datetime] + if isinstance(_updated_at, Unset): + updated_at = UNSET + else: + updated_at = isoparse(_updated_at) + + create_thread_response_200_data = cls( + id=id, + chat_id=chat_id, + message_id=message_id, + message_chat_id=message_chat_id, + updated_at=updated_at, + ) + + create_thread_response_200_data.additional_properties = d + return create_thread_response_200_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py new file mode 100644 index 0000000..100dc9c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400") + + +@_attrs_define +class DeleteMessageReactionsResponse400: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item import ( + DeleteMessageReactionsResponse400ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_400 = cls( + errors=errors, + ) + + delete_message_reactions_response_400.additional_properties = d + return delete_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py new file mode 100644 index 0000000..4a61277 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_400_errors_item_payload import ( + DeleteMessageReactionsResponse400ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse400ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_400_errors_item.additional_properties = d + return delete_message_reactions_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py new file mode 100644 index 0000000..d3d26c9 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_400_errors_item_payload = cls() + + delete_message_reactions_response_400_errors_item_payload.additional_properties = d + return delete_message_reactions_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py new file mode 100644 index 0000000..9f918a0 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404") + + +@_attrs_define +class DeleteMessageReactionsResponse404: + """ + Attributes: + errors (Union[Unset, list['DeleteMessageReactionsResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["DeleteMessageReactionsResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item import ( + DeleteMessageReactionsResponse404ErrorsItem, + ) + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = DeleteMessageReactionsResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + delete_message_reactions_response_404 = cls( + errors=errors, + ) + + delete_message_reactions_response_404.additional_properties = d + return delete_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py new file mode 100644 index 0000000..849db9d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py @@ -0,0 +1,111 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItem") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "DeleteMessageReactionsResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.delete_message_reactions_response_404_errors_item_payload import ( + DeleteMessageReactionsResponse404ErrorsItemPayload, + ) + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = DeleteMessageReactionsResponse404ErrorsItemPayload.from_dict(_payload) + + delete_message_reactions_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + delete_message_reactions_response_404_errors_item.additional_properties = d + return delete_message_reactions_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py new file mode 100644 index 0000000..f2fa5b5 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItemPayload") + + +@_attrs_define +class DeleteMessageReactionsResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + delete_message_reactions_response_404_errors_item_payload = cls() + + delete_message_reactions_response_404_errors_item_payload.additional_properties = d + return delete_message_reactions_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py new file mode 100644 index 0000000..aef4bc1 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py @@ -0,0 +1,195 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DirectResponse") + + +@_attrs_define +class DirectResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + file (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + file: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + file = self.file + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + def to_multipart(self) -> dict[str, Any]: + content_disposition = ( + self.content_disposition + if isinstance(self.content_disposition, Unset) + else (None, str(self.content_disposition).encode(), "text/plain") + ) + + acl = self.acl if isinstance(self.acl, Unset) else (None, str(self.acl).encode(), "text/plain") + + policy = self.policy if isinstance(self.policy, Unset) else (None, str(self.policy).encode(), "text/plain") + + x_amz_credential = ( + self.x_amz_credential + if isinstance(self.x_amz_credential, Unset) + else (None, str(self.x_amz_credential).encode(), "text/plain") + ) + + x_amz_algorithm = ( + self.x_amz_algorithm + if isinstance(self.x_amz_algorithm, Unset) + else (None, str(self.x_amz_algorithm).encode(), "text/plain") + ) + + x_amz_date = ( + self.x_amz_date + if isinstance(self.x_amz_date, Unset) + else (None, str(self.x_amz_date).encode(), "text/plain") + ) + + x_amz_signature = ( + self.x_amz_signature + if isinstance(self.x_amz_signature, Unset) + else (None, str(self.x_amz_signature).encode(), "text/plain") + ) + + key = self.key if isinstance(self.key, Unset) else (None, str(self.key).encode(), "text/plain") + + file = self.file if isinstance(self.file, Unset) else (None, str(self.file).encode(), "text/plain") + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = (None, str(prop).encode(), "text/plain") + + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if file is not UNSET: + field_dict["file"] = file + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + file = d.pop("file", UNSET) + + direct_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + file=file, + ) + + direct_response.additional_properties = d + return direct_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py new file mode 100644 index 0000000..cb91797 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py @@ -0,0 +1,72 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages import EditMessages + + +T = TypeVar("T", bound="EditMessageBody") + + +@_attrs_define +class EditMessageBody: + """ + Attributes: + message (Union[Unset, EditMessages]): Для получения сообщения вам необходимо знать его id и указать его в URL + запроса. + """ + + message: Union[Unset, "EditMessages"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.message, Unset): + message = self.message.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if message is not UNSET: + field_dict["message"] = message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages import EditMessages + + d = src_dict.copy() + _message = d.pop("message", UNSET) + message: Union[Unset, EditMessages] + if isinstance(_message, Unset): + message = UNSET + else: + message = EditMessages.from_dict(_message) + + edit_message_body = cls( + message=message, + ) + + edit_message_body.additional_properties = d + return edit_message_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py new file mode 100644 index 0000000..8893ed2 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="EditMessageResponse200") + + +@_attrs_define +class EditMessageResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): Созданное сообщение + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + edit_message_response_200 = cls( + data=data, + ) + + edit_message_response_200.additional_properties = d + return edit_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py new file mode 100644 index 0000000..8e6439d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py @@ -0,0 +1,113 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + +T = TypeVar("T", bound="EditMessages") + + +@_attrs_define +class EditMessages: + """Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + + Attributes: + content (Union[Unset, str]): Текст сообщения Default: 'Текст сообщения'. + files (Union[Unset, EditMessagesFiles]): + buttons (Union[Unset, list[list['EditMessagesButtonsItemItem']]]): Массив строк, каждая из которых представлена + массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в + статье. Для удаления кнопок у сообщения пришлите пустой массив. + """ + + content: Union[Unset, str] = "Текст сообщения" + files: Union[Unset, "EditMessagesFiles"] = UNSET + buttons: Union[Unset, list[list["EditMessagesButtonsItemItem"]]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content = self.content + + files: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.files, Unset): + files = self.files.to_dict() + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for buttons_item_data in self.buttons: + buttons_item = [] + for buttons_item_item_data in buttons_item_data: + buttons_item_item = buttons_item_item_data.to_dict() + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content is not UNSET: + field_dict["content"] = content + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem + from ..models.edit_messages_files import EditMessagesFiles + + d = src_dict.copy() + content = d.pop("content", UNSET) + + _files = d.pop("files", UNSET) + files: Union[Unset, EditMessagesFiles] + if isinstance(_files, Unset): + files = UNSET + else: + files = EditMessagesFiles.from_dict(_files) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for buttons_item_data in _buttons or []: + buttons_item = [] + _buttons_item = buttons_item_data + for buttons_item_item_data in _buttons_item: + buttons_item_item = EditMessagesButtonsItemItem.from_dict(buttons_item_item_data) + + buttons_item.append(buttons_item_item) + + buttons.append(buttons_item) + + edit_messages = cls( + content=content, + files=files, + buttons=buttons, + ) + + edit_messages.additional_properties = d + return edit_messages + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py new file mode 100644 index 0000000..22494f8 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py @@ -0,0 +1,76 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesButtonsItemItem") + + +@_attrs_define +class EditMessagesButtonsItemItem: + """ + Attributes: + text (Union[Unset, str]): Текст, отображаемый на кнопке пользователю + url (Union[Unset, str]): Ссылка, которая будет открыта по нажатию кнопки + data (Union[Unset, str]): Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + """ + + text: Union[Unset, str] = UNSET + url: Union[Unset, str] = UNSET + data: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text + + url = self.url + + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if text is not UNSET: + field_dict["text"] = text + if url is not UNSET: + field_dict["url"] = url + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + text = d.pop("text", UNSET) + + url = d.pop("url", UNSET) + + data = d.pop("data", UNSET) + + edit_messages_buttons_item_item = cls( + text=text, + url=url, + data=data, + ) + + edit_messages_buttons_item_item.additional_properties = d + return edit_messages_buttons_item_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py new file mode 100644 index 0000000..f42b7bb --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py @@ -0,0 +1,95 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.edit_messages_files_file_type import EditMessagesFilesFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EditMessagesFiles") + + +@_attrs_define +class EditMessagesFiles: + """ + Attributes: + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, EditMessagesFilesFileType]): + size (Union[Unset, int]): Размер файла в байтах, отображаемый пользователю Default: 1234. + """ + + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, EditMessagesFilesFileType] = UNSET + size: Union[Unset, int] = 1234 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + size = self.size + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if size is not UNSET: + field_dict["size"] = size + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, EditMessagesFilesFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = EditMessagesFilesFileType(_file_type) + + size = d.pop("size", UNSET) + + edit_messages_files = cls( + key=key, + name=name, + file_type=file_type, + size=size, + ) + + edit_messages_files.additional_properties = d + return edit_messages_files + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py new file mode 100644 index 0000000..a78a223 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class EditMessagesFilesFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py new file mode 100644 index 0000000..9011165 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py @@ -0,0 +1,275 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="Employee") + + +@_attrs_define +class Employee: + """ + Attributes: + id (Union[Unset, int]): Идентификатор пользователя Example: 1. + first_name (Union[Unset, str]): Имя + last_name (Union[Unset, str]): Фамилия + nickname (Union[Unset, str]): Имя пользователя + email (Union[Unset, str]): Электронная почта + phone_number (Union[Unset, str]): Телефон + department (Union[Unset, str]): Департамент + role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является + деактивированным. + invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) + list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику + custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника + bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) + user_status (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + title (Union[Unset, str]): Должность + created_at (Union[Unset, datetime.datetime]): Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone (Union[Unset, str]): Часовой пояс пользователя + image_url (Union[None, Unset, str]): Ссылка на скачивание аватарки + """ + + id: Union[Unset, int] = UNSET + first_name: Union[Unset, str] = UNSET + last_name: Union[Unset, str] = UNSET + nickname: Union[Unset, str] = UNSET + email: Union[Unset, str] = UNSET + phone_number: Union[Unset, str] = UNSET + department: Union[Unset, str] = UNSET + role: Union[Unset, str] = UNSET + suspended: Union[Unset, bool] = UNSET + invite_status: Union[Unset, str] = UNSET + list_tags: Union[Unset, list[str]] = UNSET + custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET + bot: Union[Unset, bool] = UNSET + user_status: Union["StatusType0", None, Unset] = UNSET + title: Union[Unset, str] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + time_zone: Union[Unset, str] = UNSET + image_url: Union[None, Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + id = self.id + + first_name = self.first_name + + last_name = self.last_name + + nickname = self.nickname + + email = self.email + + phone_number = self.phone_number + + department = self.department + + role = self.role + + suspended = self.suspended + + invite_status = self.invite_status + + list_tags: Union[Unset, list[str]] = UNSET + if not isinstance(self.list_tags, Unset): + list_tags = self.list_tags + + custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.custom_properties, Unset): + custom_properties = [] + for custom_properties_item_data in self.custom_properties: + custom_properties_item = custom_properties_item_data.to_dict() + custom_properties.append(custom_properties_item) + + bot = self.bot + + user_status: Union[None, Unset, dict[str, Any]] + if isinstance(self.user_status, Unset): + user_status = UNSET + elif isinstance(self.user_status, StatusType0): + user_status = self.user_status.to_dict() + else: + user_status = self.user_status + + title = self.title + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + time_zone = self.time_zone + + image_url: Union[None, Unset, str] + if isinstance(self.image_url, Unset): + image_url = UNSET + else: + image_url = self.image_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if first_name is not UNSET: + field_dict["first_name"] = first_name + if last_name is not UNSET: + field_dict["last_name"] = last_name + if nickname is not UNSET: + field_dict["nickname"] = nickname + if email is not UNSET: + field_dict["email"] = email + if phone_number is not UNSET: + field_dict["phone_number"] = phone_number + if department is not UNSET: + field_dict["department"] = department + if role is not UNSET: + field_dict["role"] = role + if suspended is not UNSET: + field_dict["suspended"] = suspended + if invite_status is not UNSET: + field_dict["invite_status"] = invite_status + if list_tags is not UNSET: + field_dict["list_tags"] = list_tags + if custom_properties is not UNSET: + field_dict["custom_properties"] = custom_properties + if bot is not UNSET: + field_dict["bot"] = bot + if user_status is not UNSET: + field_dict["user_status"] = user_status + if title is not UNSET: + field_dict["title"] = title + if created_at is not UNSET: + field_dict["created_at"] = created_at + if time_zone is not UNSET: + field_dict["time_zone"] = time_zone + if image_url is not UNSET: + field_dict["image_url"] = image_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + id = d.pop("id", UNSET) + + first_name = d.pop("first_name", UNSET) + + last_name = d.pop("last_name", UNSET) + + nickname = d.pop("nickname", UNSET) + + email = d.pop("email", UNSET) + + phone_number = d.pop("phone_number", UNSET) + + department = d.pop("department", UNSET) + + role = d.pop("role", UNSET) + + suspended = d.pop("suspended", UNSET) + + invite_status = d.pop("invite_status", UNSET) + + list_tags = cast(list[str], d.pop("list_tags", UNSET)) + + custom_properties = [] + _custom_properties = d.pop("custom_properties", UNSET) + for custom_properties_item_data in _custom_properties or []: + custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) + + custom_properties.append(custom_properties_item) + + bot = d.pop("bot", UNSET) + + def _parse_user_status(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + user_status = _parse_user_status(d.pop("user_status", UNSET)) + + title = d.pop("title", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + time_zone = d.pop("time_zone", UNSET) + + def _parse_image_url(data: object) -> Union[None, Unset, str]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, str], data) + + image_url = _parse_image_url(d.pop("image_url", UNSET)) + + employee = cls( + id=id, + first_name=first_name, + last_name=last_name, + nickname=nickname, + email=email, + phone_number=phone_number, + department=department, + role=role, + suspended=suspended, + invite_status=invite_status, + list_tags=list_tags, + custom_properties=custom_properties, + bot=bot, + user_status=user_status, + title=title, + created_at=created_at, + time_zone=time_zone, + image_url=image_url, + ) + + employee.additional_properties = d + return employee + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py new file mode 100644 index 0000000..e9e73d2 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error_payload import ErrorPayload + + +T = TypeVar("T", bound="Error") + + +@_attrs_define +class Error: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error_payload import ErrorPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorPayload.from_dict(_payload) + + error = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + error.additional_properties = d + return error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py new file mode 100644 index 0000000..9133249 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorPayload") + + +@_attrs_define +class ErrorPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error_payload = cls() + + error_payload.additional_properties = d + return error_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py new file mode 100644 index 0000000..52b0dee --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py @@ -0,0 +1,108 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code_payload import ErrorsCodePayload + + +T = TypeVar("T", bound="ErrorsCode") + + +@_attrs_define +class ErrorsCode: + """Bad Request + + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, ErrorsCodePayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "ErrorsCodePayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code_payload import ErrorsCodePayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, ErrorsCodePayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = ErrorsCodePayload.from_dict(_payload) + + errors_code = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + errors_code.additional_properties = d + return errors_code + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py new file mode 100644 index 0000000..8128de2 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorsCodePayload") + + +@_attrs_define +class ErrorsCodePayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + errors_code_payload = cls() + + errors_code_payload.additional_properties = d + return errors_code_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py new file mode 100644 index 0000000..5bb1dc4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py @@ -0,0 +1,130 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FileResponse") + + +@_attrs_define +class FileResponse: + """ + Attributes: + content_disposition (Union[Unset, str]): + acl (Union[Unset, str]): + policy (Union[Unset, str]): + x_amz_credential (Union[Unset, str]): + x_amz_algorithm (Union[Unset, str]): + x_amz_date (Union[Unset, str]): + x_amz_signature (Union[Unset, str]): + key (Union[Unset, str]): + direct_url (Union[Unset, str]): + """ + + content_disposition: Union[Unset, str] = UNSET + acl: Union[Unset, str] = UNSET + policy: Union[Unset, str] = UNSET + x_amz_credential: Union[Unset, str] = UNSET + x_amz_algorithm: Union[Unset, str] = UNSET + x_amz_date: Union[Unset, str] = UNSET + x_amz_signature: Union[Unset, str] = UNSET + key: Union[Unset, str] = UNSET + direct_url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content_disposition = self.content_disposition + + acl = self.acl + + policy = self.policy + + x_amz_credential = self.x_amz_credential + + x_amz_algorithm = self.x_amz_algorithm + + x_amz_date = self.x_amz_date + + x_amz_signature = self.x_amz_signature + + key = self.key + + direct_url = self.direct_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if content_disposition is not UNSET: + field_dict["Content-Disposition"] = content_disposition + if acl is not UNSET: + field_dict["acl"] = acl + if policy is not UNSET: + field_dict["policy"] = policy + if x_amz_credential is not UNSET: + field_dict["x-amz-credential"] = x_amz_credential + if x_amz_algorithm is not UNSET: + field_dict["x-amz-algorithm"] = x_amz_algorithm + if x_amz_date is not UNSET: + field_dict["x-amz-date"] = x_amz_date + if x_amz_signature is not UNSET: + field_dict["x-amz-signature"] = x_amz_signature + if key is not UNSET: + field_dict["key"] = key + if direct_url is not UNSET: + field_dict["direct_url"] = direct_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + content_disposition = d.pop("Content-Disposition", UNSET) + + acl = d.pop("acl", UNSET) + + policy = d.pop("policy", UNSET) + + x_amz_credential = d.pop("x-amz-credential", UNSET) + + x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) + + x_amz_date = d.pop("x-amz-date", UNSET) + + x_amz_signature = d.pop("x-amz-signature", UNSET) + + key = d.pop("key", UNSET) + + direct_url = d.pop("direct_url", UNSET) + + file_response = cls( + content_disposition=content_disposition, + acl=acl, + policy=policy, + x_amz_credential=x_amz_credential, + x_amz_algorithm=x_amz_algorithm, + x_amz_date=x_amz_date, + x_amz_signature=x_amz_signature, + key=key, + direct_url=direct_url, + ) + + file_response.additional_properties = d + return file_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py new file mode 100644 index 0000000..274ed8c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatResponse200") + + +@_attrs_define +class GetChatResponse200: + """ + Attributes: + data (Union[Unset, Chat]): Беседа или канал + """ + + data: Union[Unset, "Chat"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Chat] + if isinstance(_data, Unset): + data = UNSET + else: + data = Chat.from_dict(_data) + + get_chat_response_200 = cls( + data=data, + ) + + get_chat_response_200.additional_properties = d + return get_chat_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py new file mode 100644 index 0000000..6aaf8b1 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatResponse404") + + +@_attrs_define +class GetChatResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chat_response_404 = cls( + errors=errors, + ) + + get_chat_response_404.additional_properties = d + return get_chat_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py new file mode 100644 index 0000000..b76cb4d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsAvailability(str, Enum): + IS_MEMBER = "is_member" + PUBLIC = "public" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py new file mode 100644 index 0000000..3917a9f --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.chat import Chat + + +T = TypeVar("T", bound="GetChatsResponse200") + + +@_attrs_define +class GetChatsResponse200: + """ + Attributes: + data (Union[Unset, list['Chat']]): + """ + + data: Union[Unset, list["Chat"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.chat import Chat + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Chat.from_dict(data_item_data) + + data.append(data_item) + + get_chats_response_200 = cls( + data=data, + ) + + get_chats_response_200.additional_properties = d + return get_chats_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py new file mode 100644 index 0000000..005a6a3 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.errors_code import ErrorsCode + + +T = TypeVar("T", bound="GetChatsResponse400") + + +@_attrs_define +class GetChatsResponse400: + """ + Attributes: + errors (Union[Unset, ErrorsCode]): Bad Request + """ + + errors: Union[Unset, "ErrorsCode"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.errors, Unset): + errors = self.errors.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.errors_code import ErrorsCode + + d = src_dict.copy() + _errors = d.pop("errors", UNSET) + errors: Union[Unset, ErrorsCode] + if isinstance(_errors, Unset): + errors = UNSET + else: + errors = ErrorsCode.from_dict(_errors) + + get_chats_response_400 = cls( + errors=errors, + ) + + get_chats_response_400.additional_properties = d + return get_chats_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py new file mode 100644 index 0000000..1553a65 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse404") + + +@_attrs_define +class GetChatsResponse404: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_404 = cls( + errors=errors, + ) + + get_chats_response_404.additional_properties = d + return get_chats_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py new file mode 100644 index 0000000..5248609 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.error import Error + + +T = TypeVar("T", bound="GetChatsResponse422") + + +@_attrs_define +class GetChatsResponse422: + """ + Attributes: + errors (Union[Unset, list['Error']]): + """ + + errors: Union[Unset, list["Error"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for componentsschemas_errors_item_data in self.errors: + componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() + errors.append(componentsschemas_errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.error import Error + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for componentsschemas_errors_item_data in _errors or []: + componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) + + errors.append(componentsschemas_errors_item) + + get_chats_response_422 = cls( + errors=errors, + ) + + get_chats_response_422.additional_properties = d + return get_chats_response_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py new file mode 100644 index 0000000..0de410c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GetChatsSortid(str, Enum): + ASC = "asc" + DESC = "desc" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py new file mode 100644 index 0000000..93ea91d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_common_methods import QueryCommonMethods + + +T = TypeVar("T", bound="GetCommonMethodsResponse200") + + +@_attrs_define +class GetCommonMethodsResponse200: + """ + Attributes: + data (Union[Unset, list['QueryCommonMethods']]): + """ + + data: Union[Unset, list["QueryCommonMethods"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_common_methods import QueryCommonMethods + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = QueryCommonMethods.from_dict(data_item_data) + + data.append(data_item) + + get_common_methods_response_200 = cls( + data=data, + ) + + get_common_methods_response_200.additional_properties = d + return get_common_methods_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py new file mode 100644 index 0000000..b970ea8 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeeResponse200") + + +@_attrs_define +class GetEmployeeResponse200: + """ + Attributes: + data (Union[Unset, Employee]): + """ + + data: Union[Unset, "Employee"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Employee] + if isinstance(_data, Unset): + data = UNSET + else: + data = Employee.from_dict(_data) + + get_employee_response_200 = cls( + data=data, + ) + + get_employee_response_200.additional_properties = d + return get_employee_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py new file mode 100644 index 0000000..978802c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.employee import Employee + + +T = TypeVar("T", bound="GetEmployeesResponse200") + + +@_attrs_define +class GetEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['Employee']]): + """ + + data: Union[Unset, list["Employee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.employee import Employee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Employee.from_dict(data_item_data) + + data.append(data_item) + + get_employees_response_200 = cls( + data=data, + ) + + get_employees_response_200.additional_properties = d + return get_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py new file mode 100644 index 0000000..52837e1 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetListMessageResponse200") + + +@_attrs_define +class GetListMessageResponse200: + """ + Attributes: + data (Union[Unset, list['Message']]): + """ + + data: Union[Unset, list["Message"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Message.from_dict(data_item_data) + + data.append(data_item) + + get_list_message_response_200 = cls( + data=data, + ) + + get_list_message_response_200.additional_properties = d + return get_list_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py new file mode 100644 index 0000000..eaa7bb5 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py @@ -0,0 +1,68 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="GetMessageReactionsBody") + + +@_attrs_define +class GetMessageReactionsBody: + """ + Attributes: + per (Union[Unset, int]): Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). + Default: 50. + page (Union[Unset, int]): Номер страницы выборки (по умолчанию 1). Default: 1. + """ + + per: Union[Unset, int] = 50 + page: Union[Unset, int] = 1 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + per = self.per + + page = self.page + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if per is not UNSET: + field_dict["per"] = per + if page is not UNSET: + field_dict["page"] = page + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + per = d.pop("per", UNSET) + + page = d.pop("page", UNSET) + + get_message_reactions_body = cls( + per=per, + page=page, + ) + + get_message_reactions_body.additional_properties = d + return get_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py new file mode 100644 index 0000000..3c50c79 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.reaction import Reaction + + +T = TypeVar("T", bound="GetMessageReactionsResponse200") + + +@_attrs_define +class GetMessageReactionsResponse200: + """ + Attributes: + data (Union[Unset, list['Reaction']]): + """ + + data: Union[Unset, list["Reaction"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.reaction import Reaction + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Reaction.from_dict(data_item_data) + + data.append(data_item) + + get_message_reactions_response_200 = cls( + data=data, + ) + + get_message_reactions_response_200.additional_properties = d + return get_message_reactions_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py new file mode 100644 index 0000000..677295d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message import Message + + +T = TypeVar("T", bound="GetMessageResponse200") + + +@_attrs_define +class GetMessageResponse200: + """ + Attributes: + data (Union[Unset, Message]): + """ + + data: Union[Unset, "Message"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.message import Message + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Message] + if isinstance(_data, Unset): + data = UNSET + else: + data = Message.from_dict(_data) + + get_message_response_200 = cls( + data=data, + ) + + get_message_response_200.additional_properties = d + return get_message_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py new file mode 100644 index 0000000..7e93886 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="GetStatusResponse200") + + +@_attrs_define +class GetStatusResponse200: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + get_status_response_200 = cls( + data=data, + ) + + get_status_response_200.additional_properties = d + return get_status_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py new file mode 100644 index 0000000..188f734 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagResponse200") + + +@_attrs_define +class GetTagResponse200: + """ + Attributes: + data (Union[Unset, Tag]): Для получения тега вам необходимо знать его id и указать его в URL запроса. + """ + + data: Union[Unset, "Tag"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data, Unset): + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + _data = d.pop("data", UNSET) + data: Union[Unset, Tag] + if isinstance(_data, Unset): + data = UNSET + else: + data = Tag.from_dict(_data) + + get_tag_response_200 = cls( + data=data, + ) + + get_tag_response_200.additional_properties = d + return get_tag_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py new file mode 100644 index 0000000..c3c8ead --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + +T = TypeVar("T", bound="GetTagResponse404") + + +@_attrs_define +class GetTagResponse404: + """ + Attributes: + errors (Union[Unset, list['GetTagResponse404ErrorsItem']]): Список ошибок. + """ + + errors: Union[Unset, list["GetTagResponse404ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagResponse404ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tag_response_404 = cls( + errors=errors, + ) + + get_tag_response_404.additional_properties = d + return get_tag_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py new file mode 100644 index 0000000..18649e6 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagResponse404ErrorsItem") + + +@_attrs_define +class GetTagResponse404ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): + value (Union[Unset, str]): + message (Union[Unset, str]): + code (Union[Unset, str]): + payload (Union[Unset, GetTagResponse404ErrorsItemPayload]): + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagResponse404ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagResponse404ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagResponse404ErrorsItemPayload.from_dict(_payload) + + get_tag_response_404_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tag_response_404_errors_item.additional_properties = d + return get_tag_response_404_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py new file mode 100644 index 0000000..b6d7c6c --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagResponse404ErrorsItemPayload") + + +@_attrs_define +class GetTagResponse404ErrorsItemPayload: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tag_response_404_errors_item_payload = cls() + + get_tag_response_404_errors_item_payload.additional_properties = d + return get_tag_response_404_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py new file mode 100644 index 0000000..682b3fa --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.base_employee import BaseEmployee + + +T = TypeVar("T", bound="GetTagsEmployeesResponse200") + + +@_attrs_define +class GetTagsEmployeesResponse200: + """ + Attributes: + data (Union[Unset, list['BaseEmployee']]): + """ + + data: Union[Unset, list["BaseEmployee"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.base_employee import BaseEmployee + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = BaseEmployee.from_dict(data_item_data) + + data.append(data_item) + + get_tags_employees_response_200 = cls( + data=data, + ) + + get_tags_employees_response_200.additional_properties = d + return get_tags_employees_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py new file mode 100644 index 0000000..1ae18d4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tag import Tag + + +T = TypeVar("T", bound="GetTagsResponse200") + + +@_attrs_define +class GetTagsResponse200: + """ + Attributes: + data (Union[Unset, list['Tag']]): + """ + + data: Union[Unset, list["Tag"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.data, Unset): + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() + data.append(data_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.tag import Tag + + d = src_dict.copy() + data = [] + _data = d.pop("data", UNSET) + for data_item_data in _data or []: + data_item = Tag.from_dict(data_item_data) + + data.append(data_item) + + get_tags_response_200 = cls( + data=data, + ) + + get_tags_response_200.additional_properties = d + return get_tags_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py new file mode 100644 index 0000000..1865c60 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py @@ -0,0 +1,74 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + +T = TypeVar("T", bound="GetTagsResponse400") + + +@_attrs_define +class GetTagsResponse400: + """ + Attributes: + errors (Union[Unset, list['GetTagsResponse400ErrorsItem']]): Список ошибок в запросе. + """ + + errors: Union[Unset, list["GetTagsResponse400ErrorsItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if errors is not UNSET: + field_dict["errors"] = errors + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem + + d = src_dict.copy() + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = GetTagsResponse400ErrorsItem.from_dict(errors_item_data) + + errors.append(errors_item) + + get_tags_response_400 = cls( + errors=errors, + ) + + get_tags_response_400.additional_properties = d + return get_tags_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py new file mode 100644 index 0000000..bd7859d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py @@ -0,0 +1,107 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItem") + + +@_attrs_define +class GetTagsResponse400ErrorsItem: + """ + Attributes: + key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. + value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. + message (Union[Unset, str]): Текстовое описание ошибки. + code (Union[Unset, str]): Внутренний код ошибки. + payload (Union[Unset, GetTagsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. + """ + + key: Union[Unset, str] = UNSET + value: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + code: Union[Unset, str] = UNSET + payload: Union[Unset, "GetTagsResponse400ErrorsItemPayload"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key = self.key + + value = self.value + + message = self.message + + code = self.code + + payload: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.payload, Unset): + payload = self.payload.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if key is not UNSET: + field_dict["key"] = key + if value is not UNSET: + field_dict["value"] = value + if message is not UNSET: + field_dict["message"] = message + if code is not UNSET: + field_dict["code"] = code + if payload is not UNSET: + field_dict["payload"] = payload + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload + + d = src_dict.copy() + key = d.pop("key", UNSET) + + value = d.pop("value", UNSET) + + message = d.pop("message", UNSET) + + code = d.pop("code", UNSET) + + _payload = d.pop("payload", UNSET) + payload: Union[Unset, GetTagsResponse400ErrorsItemPayload] + if isinstance(_payload, Unset): + payload = UNSET + else: + payload = GetTagsResponse400ErrorsItemPayload.from_dict(_payload) + + get_tags_response_400_errors_item = cls( + key=key, + value=value, + message=message, + code=code, + payload=payload, + ) + + get_tags_response_400_errors_item.additional_properties = d + return get_tags_response_400_errors_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py new file mode 100644 index 0000000..2e1d941 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py @@ -0,0 +1,43 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GetTagsResponse400ErrorsItemPayload") + + +@_attrs_define +class GetTagsResponse400ErrorsItemPayload: + """Дополнительная информация об ошибке.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + get_tags_response_400_errors_item_payload = cls() + + get_tags_response_400_errors_item_payload.additional_properties = d + return get_tags_response_400_errors_item_payload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py new file mode 100644 index 0000000..bb01030 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py @@ -0,0 +1,272 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..models.message_entity_type import MessageEntityType +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + +T = TypeVar("T", bound="Message") + + +@_attrs_define +class Message: + """ + Attributes: + entity_type (Union[Unset, MessageEntityType]): Default: MessageEntityType.DISCUSSION. + entity_id (Union[Unset, int]): + content (Union[Unset, str]): + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + user_id (Union[Unset, int]): + created_at (Union[Unset, datetime.datetime]): + files (Union[Unset, list['MessageFilesItem']]): + buttons (Union[Unset, list[list['Button']]]): + thread (Union['MessageThread', None, Unset]): + forwarding (Union['MessageForwarding', None, Unset]): + parent_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому написан ответ. Возвращается как + null, если сообщение не является ответом. + """ + + entity_type: Union[Unset, MessageEntityType] = MessageEntityType.DISCUSSION + entity_id: Union[Unset, int] = UNSET + content: Union[Unset, str] = UNSET + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + files: Union[Unset, list["MessageFilesItem"]] = UNSET + buttons: Union[Unset, list[list["Button"]]] = UNSET + thread: Union["MessageThread", None, Unset] = UNSET + forwarding: Union["MessageForwarding", None, Unset] = UNSET + parent_message_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + entity_type: Union[Unset, str] = UNSET + if not isinstance(self.entity_type, Unset): + entity_type = self.entity_type.value + + entity_id = self.entity_id + + content = self.content + + id = self.id + + chat_id = self.chat_id + + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + files: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.files, Unset): + files = [] + for files_item_data in self.files: + files_item = files_item_data.to_dict() + files.append(files_item) + + buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET + if not isinstance(self.buttons, Unset): + buttons = [] + for componentsschemas_buttons_item_data in self.buttons: + componentsschemas_buttons_item = [] + for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: + componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + thread: Union[None, Unset, dict[str, Any]] + if isinstance(self.thread, Unset): + thread = UNSET + elif isinstance(self.thread, MessageThread): + thread = self.thread.to_dict() + else: + thread = self.thread + + forwarding: Union[None, Unset, dict[str, Any]] + if isinstance(self.forwarding, Unset): + forwarding = UNSET + elif isinstance(self.forwarding, MessageForwarding): + forwarding = self.forwarding.to_dict() + else: + forwarding = self.forwarding + + parent_message_id: Union[None, Unset, int] + if isinstance(self.parent_message_id, Unset): + parent_message_id = UNSET + else: + parent_message_id = self.parent_message_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if entity_type is not UNSET: + field_dict["entity_type"] = entity_type + if entity_id is not UNSET: + field_dict["entity_id"] = entity_id + if content is not UNSET: + field_dict["content"] = content + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if files is not UNSET: + field_dict["files"] = files + if buttons is not UNSET: + field_dict["buttons"] = buttons + if thread is not UNSET: + field_dict["thread"] = thread + if forwarding is not UNSET: + field_dict["forwarding"] = forwarding + if parent_message_id is not UNSET: + field_dict["parent_message_id"] = parent_message_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.button import Button + from ..models.message_files_item import MessageFilesItem + from ..models.message_forwarding import MessageForwarding + from ..models.message_thread import MessageThread + + d = src_dict.copy() + _entity_type = d.pop("entity_type", UNSET) + entity_type: Union[Unset, MessageEntityType] + if isinstance(_entity_type, Unset): + entity_type = UNSET + else: + entity_type = MessageEntityType(_entity_type) + + entity_id = d.pop("entity_id", UNSET) + + content = d.pop("content", UNSET) + + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + files = [] + _files = d.pop("files", UNSET) + for files_item_data in _files or []: + files_item = MessageFilesItem.from_dict(files_item_data) + + files.append(files_item) + + buttons = [] + _buttons = d.pop("buttons", UNSET) + for componentsschemas_buttons_item_data in _buttons or []: + componentsschemas_buttons_item = [] + _componentsschemas_buttons_item = componentsschemas_buttons_item_data + for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: + componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) + + componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) + + buttons.append(componentsschemas_buttons_item) + + def _parse_thread(data: object) -> Union["MessageThread", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + thread_type_0 = MessageThread.from_dict(data) + + return thread_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageThread", None, Unset], data) + + thread = _parse_thread(d.pop("thread", UNSET)) + + def _parse_forwarding(data: object) -> Union["MessageForwarding", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + forwarding_type_0 = MessageForwarding.from_dict(data) + + return forwarding_type_0 + except: # noqa: E722 + pass + return cast(Union["MessageForwarding", None, Unset], data) + + forwarding = _parse_forwarding(d.pop("forwarding", UNSET)) + + def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) + + message = cls( + entity_type=entity_type, + entity_id=entity_id, + content=content, + id=id, + chat_id=chat_id, + user_id=user_id, + created_at=created_at, + files=files, + buttons=buttons, + thread=thread, + forwarding=forwarding, + parent_message_id=parent_message_id, + ) + + message.additional_properties = d + return message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py new file mode 100644 index 0000000..e8a126a --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class MessageEntityType(str, Enum): + DISCUSSION = "discussion" + THREAD = "thread" + USER = "user" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py new file mode 100644 index 0000000..21509d2 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py @@ -0,0 +1,104 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.message_files_item_file_type import MessageFilesItemFileType +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageFilesItem") + + +@_attrs_define +class MessageFilesItem: + """ + Attributes: + id (Union[Unset, int]): + key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении + должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе + с расширением) + file_type (Union[Unset, MessageFilesItemFileType]): + url (Union[Unset, str]): Размер файла в байтах, отображаемый пользователю + """ + + id: Union[Unset, int] = UNSET + key: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + file_type: Union[Unset, MessageFilesItemFileType] = UNSET + url: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + key = self.key + + name = self.name + + file_type: Union[Unset, str] = UNSET + if not isinstance(self.file_type, Unset): + file_type = self.file_type.value + + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if key is not UNSET: + field_dict["key"] = key + if name is not UNSET: + field_dict["name"] = name + if file_type is not UNSET: + field_dict["file_type"] = file_type + if url is not UNSET: + field_dict["url"] = url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + key = d.pop("key", UNSET) + + name = d.pop("name", UNSET) + + _file_type = d.pop("file_type", UNSET) + file_type: Union[Unset, MessageFilesItemFileType] + if isinstance(_file_type, Unset): + file_type = UNSET + else: + file_type = MessageFilesItemFileType(_file_type) + + url = d.pop("url", UNSET) + + message_files_item = cls( + id=id, + key=key, + name=name, + file_type=file_type, + url=url, + ) + + message_files_item.additional_properties = d + return message_files_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py new file mode 100644 index 0000000..1e00e5b --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class MessageFilesItemFileType(str, Enum): + FILE = "file" + IMAGE = "image" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py new file mode 100644 index 0000000..6ce981d --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py @@ -0,0 +1,153 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageForwarding") + + +@_attrs_define +class MessageForwarding: + """ + Attributes: + original_message_id (Union[Unset, int]): Идентификатор оригинального сообщения + original_chat_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + author_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение + original_created_at (Union[Unset, int]): Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в + формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id (Union[None, Unset, int]): Идентификатор треда, в котором находится оригинальное сообщение. + Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому был создан тред, в + котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + original_thread_parent_chat_id (Union[None, Unset, int]): Идентификатор чата сообщения, к которому был создан + тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является + комментарием в треде. + """ + + original_message_id: Union[Unset, int] = UNSET + original_chat_id: Union[Unset, int] = UNSET + author_id: Union[Unset, int] = UNSET + original_created_at: Union[Unset, int] = UNSET + original_thread_id: Union[None, Unset, int] = UNSET + original_thread_message_id: Union[None, Unset, int] = UNSET + original_thread_parent_chat_id: Union[None, Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + original_message_id = self.original_message_id + + original_chat_id = self.original_chat_id + + author_id = self.author_id + + original_created_at = self.original_created_at + + original_thread_id: Union[None, Unset, int] + if isinstance(self.original_thread_id, Unset): + original_thread_id = UNSET + else: + original_thread_id = self.original_thread_id + + original_thread_message_id: Union[None, Unset, int] + if isinstance(self.original_thread_message_id, Unset): + original_thread_message_id = UNSET + else: + original_thread_message_id = self.original_thread_message_id + + original_thread_parent_chat_id: Union[None, Unset, int] + if isinstance(self.original_thread_parent_chat_id, Unset): + original_thread_parent_chat_id = UNSET + else: + original_thread_parent_chat_id = self.original_thread_parent_chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if original_message_id is not UNSET: + field_dict["original_message_id"] = original_message_id + if original_chat_id is not UNSET: + field_dict["original_chat_id"] = original_chat_id + if author_id is not UNSET: + field_dict["author_id"] = author_id + if original_created_at is not UNSET: + field_dict["original_created_at"] = original_created_at + if original_thread_id is not UNSET: + field_dict["original_thread_id"] = original_thread_id + if original_thread_message_id is not UNSET: + field_dict["original_thread_message_id"] = original_thread_message_id + if original_thread_parent_chat_id is not UNSET: + field_dict["original_thread_parent_chat_id"] = original_thread_parent_chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + original_message_id = d.pop("original_message_id", UNSET) + + original_chat_id = d.pop("original_chat_id", UNSET) + + author_id = d.pop("author_id", UNSET) + + original_created_at = d.pop("original_created_at", UNSET) + + def _parse_original_thread_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_id = _parse_original_thread_id(d.pop("original_thread_id", UNSET)) + + def _parse_original_thread_message_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_message_id = _parse_original_thread_message_id(d.pop("original_thread_message_id", UNSET)) + + def _parse_original_thread_parent_chat_id(data: object) -> Union[None, Unset, int]: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(Union[None, Unset, int], data) + + original_thread_parent_chat_id = _parse_original_thread_parent_chat_id( + d.pop("original_thread_parent_chat_id", UNSET) + ) + + message_forwarding = cls( + original_message_id=original_message_id, + original_chat_id=original_chat_id, + author_id=author_id, + original_created_at=original_created_at, + original_thread_id=original_thread_id, + original_thread_message_id=original_thread_message_id, + original_thread_parent_chat_id=original_thread_parent_chat_id, + ) + + message_forwarding.additional_properties = d + return message_forwarding + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py new file mode 100644 index 0000000..ddd18f0 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py @@ -0,0 +1,67 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="MessageThread") + + +@_attrs_define +class MessageThread: + """ + Attributes: + id (Union[Unset, int]): + chat_id (Union[Unset, int]): + """ + + id: Union[Unset, int] = UNSET + chat_id: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + chat_id = self.chat_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if chat_id is not UNSET: + field_dict["chat_id"] = chat_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + chat_id = d.pop("chat_id", UNSET) + + message_thread = cls( + id=id, + chat_id=chat_id, + ) + + message_thread.additional_properties = d + return message_thread + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py new file mode 100644 index 0000000..c24e928 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py @@ -0,0 +1,59 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="NotFound") + + +@_attrs_define +class NotFound: + """Объект не найден + + Attributes: + detail (Union[Unset, str]): Описание ошибки Example: Страница не найдена.. + """ + + detail: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if detail is not UNSET: + field_dict["detail"] = detail + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + detail = d.pop("detail", UNSET) + + not_found = cls( + detail=detail, + ) + + not_found.additional_properties = d + return not_found + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py new file mode 100644 index 0000000..620f8dc --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py @@ -0,0 +1,69 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMembersToChatsBody") + + +@_attrs_define +class PostMembersToChatsBody: + """ + Attributes: + member_ids (list[int]): Example: [186, 187]. + silent (Union[Unset, bool]): + """ + + member_ids: list[int] + silent: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + member_ids = self.member_ids + + silent = self.silent + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "member_ids": member_ids, + } + ) + if silent is not UNSET: + field_dict["silent"] = silent + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + member_ids = cast(list[int], d.pop("member_ids")) + + silent = d.pop("silent", UNSET) + + post_members_to_chats_body = cls( + member_ids=member_ids, + silent=silent, + ) + + post_members_to_chats_body.additional_properties = d + return post_members_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py new file mode 100644 index 0000000..fffa22a --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostMessageReactionsBody") + + +@_attrs_define +class PostMessageReactionsBody: + """ + Attributes: + code (str): Emoji в строковом формате для добавления реакции. + """ + + code: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "code": code, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + code = d.pop("code") + + post_message_reactions_body = cls( + code=code, + ) + + post_message_reactions_body.additional_properties = d + return post_message_reactions_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py new file mode 100644 index 0000000..50b0078 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse400") + + +@_attrs_define +class PostMessageReactionsResponse400: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_400 = cls( + error=error, + ) + + post_message_reactions_response_400.additional_properties = d + return post_message_reactions_response_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py new file mode 100644 index 0000000..cd52780 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse403") + + +@_attrs_define +class PostMessageReactionsResponse403: + """ + Attributes: + error (Union[Unset, str]): Описание ошибки. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_403 = cls( + error=error, + ) + + post_message_reactions_response_403.additional_properties = d + return post_message_reactions_response_403 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py new file mode 100644 index 0000000..1a26c89 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PostMessageReactionsResponse404") + + +@_attrs_define +class PostMessageReactionsResponse404: + """ + Attributes: + error (Union[Unset, str]): Сообщение не найдено. + """ + + error: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + error = d.pop("error", UNSET) + + post_message_reactions_response_404 = cls( + error=error, + ) + + post_message_reactions_response_404.additional_properties = d + return post_message_reactions_response_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py new file mode 100644 index 0000000..23040f4 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PostTagsToChatsBody") + + +@_attrs_define +class PostTagsToChatsBody: + """ + Attributes: + group_tag_ids (list[int]): Example: [86, 18]. + """ + + group_tag_ids: list[int] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + group_tag_ids = self.group_tag_ids + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "group_tag_ids": group_tag_ids, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + group_tag_ids = cast(list[int], d.pop("group_tag_ids")) + + post_tags_to_chats_body = cls( + group_tag_ids=group_tag_ids, + ) + + post_tags_to_chats_body.additional_properties = d + return post_tags_to_chats_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py new file mode 100644 index 0000000..a34d4e0 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py @@ -0,0 +1,88 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.status_type_0 import StatusType0 + + +T = TypeVar("T", bound="PutStatusResponse201") + + +@_attrs_define +class PutStatusResponse201: + """ + Attributes: + data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. + """ + + data: Union["StatusType0", None, Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.status_type_0 import StatusType0 + + data: Union[None, Unset, dict[str, Any]] + if isinstance(self.data, Unset): + data = UNSET + elif isinstance(self.data, StatusType0): + data = self.data.to_dict() + else: + data = self.data + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if data is not UNSET: + field_dict["data"] = data + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.status_type_0 import StatusType0 + + d = src_dict.copy() + + def _parse_data(data: object) -> Union["StatusType0", None, Unset]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_status_type_0 = StatusType0.from_dict(data) + + return componentsschemas_status_type_0 + except: # noqa: E722 + pass + return cast(Union["StatusType0", None, Unset], data) + + data = _parse_data(d.pop("data", UNSET)) + + put_status_response_201 = cls( + data=data, + ) + + put_status_response_201.additional_properties = d + return put_status_response_201 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py new file mode 100644 index 0000000..f3e1788 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py @@ -0,0 +1,91 @@ +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryChat") + + +@_attrs_define +class QueryChat: + """Собранный объект параметров создаваемой беседы или канала + + Attributes: + name (str): Название Example: 🤿 aqua. + member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, которые станут участниками Example: + [186, 187]. + channel (Union[Unset, bool]): Тип: беседа (по умолчанию, false) или канал (true) Example: True. + public (Union[Unset, bool]): Доступ: закрытый (по умолчанию, false) или открытый (true) + """ + + name: str + member_ids: Union[Unset, list[int]] = UNSET + channel: Union[Unset, bool] = UNSET + public: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + member_ids: Union[Unset, list[int]] = UNSET + if not isinstance(self.member_ids, Unset): + member_ids = self.member_ids + + channel = self.channel + + public = self.public + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if member_ids is not UNSET: + field_dict["member_ids"] = member_ids + if channel is not UNSET: + field_dict["channel"] = channel + if public is not UNSET: + field_dict["public"] = public + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + member_ids = cast(list[int], d.pop("member_ids", UNSET)) + + channel = d.pop("channel", UNSET) + + public = d.pop("public", UNSET) + + query_chat = cls( + name=name, + member_ids=member_ids, + channel=channel, + public=public, + ) + + query_chat.additional_properties = d + return query_chat + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py new file mode 100644 index 0000000..f575b43 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryCommonMethods") + + +@_attrs_define +class QueryCommonMethods: + """получение списка актульных полей сущности. + + Attributes: + id (Union[Unset, int]): Название поля Example: 1. + name (Union[Unset, str]): Идентификатор поля Example: Дата рождения. + data_type (Union[Unset, str]): тип поля (string, number, date или link) Example: number. + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + data_type: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + data_type = self.data_type + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if data_type is not UNSET: + field_dict["data_type"] = data_type + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + data_type = d.pop("data_type", UNSET) + + query_common_methods = cls( + id=id, + name=name, + data_type=data_type, + ) + + query_common_methods.additional_properties = d + return query_common_methods + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py new file mode 100644 index 0000000..885c9fc --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py @@ -0,0 +1,71 @@ +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_status_status import QueryStatusStatus + + +T = TypeVar("T", bound="QueryStatus") + + +@_attrs_define +class QueryStatus: + """ + Attributes: + status (Union[Unset, QueryStatusStatus]): Собранный объект параметров нового статуса + """ + + status: Union[Unset, "QueryStatusStatus"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.status, Unset): + status = self.status.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if status is not UNSET: + field_dict["status"] = status + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.query_status_status import QueryStatusStatus + + d = src_dict.copy() + _status = d.pop("status", UNSET) + status: Union[Unset, QueryStatusStatus] + if isinstance(_status, Unset): + status = UNSET + else: + status = QueryStatusStatus.from_dict(_status) + + query_status = cls( + status=status, + ) + + query_status.additional_properties = d + return query_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py new file mode 100644 index 0000000..48858ea --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py @@ -0,0 +1,102 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryStatusStatus") + + +@_attrs_define +class QueryStatusStatus: + """Собранный объект параметров нового статуса + + Attributes: + emoji (str): Emoji символ статуса + title (str): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ + """ + + emoji: str + title: str + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "emoji": emoji, + "title": title, + } + ) + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji") + + title = d.pop("title") + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + query_status_status = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + query_status_status.additional_properties = d + return query_status_status + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py new file mode 100644 index 0000000..de28f69 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py @@ -0,0 +1,86 @@ +import datetime +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Reaction") + + +@_attrs_define +class Reaction: + """ + Attributes: + user_id (Union[Unset, int]): Идентификатор пользователя, оставившего реакцию. + created_at (Union[Unset, datetime.datetime]): Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY- + MM-DDThh:mm:ss.sssZ. + code (Union[Unset, str]): Emoji символ реакции. + """ + + user_id: Union[Unset, int] = UNSET + created_at: Union[Unset, datetime.datetime] = UNSET + code: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + created_at: Union[Unset, str] = UNSET + if not isinstance(self.created_at, Unset): + created_at = self.created_at.isoformat() + + code = self.code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if user_id is not UNSET: + field_dict["user_id"] = user_id + if created_at is not UNSET: + field_dict["created_at"] = created_at + if code is not UNSET: + field_dict["code"] = code + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + user_id = d.pop("user_id", UNSET) + + _created_at = d.pop("created_at", UNSET) + created_at: Union[Unset, datetime.datetime] + if isinstance(_created_at, Unset): + created_at = UNSET + else: + created_at = isoparse(_created_at) + + code = d.pop("code", UNSET) + + reaction = cls( + user_id=user_id, + created_at=created_at, + code=code, + ) + + reaction.additional_properties = d + return reaction + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py new file mode 100644 index 0000000..8997cfe --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py @@ -0,0 +1,101 @@ +import datetime +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="StatusType0") + + +@_attrs_define +class StatusType0: + """Статус. Возвращается как null, если статус не установлен. + + Attributes: + emoji (Union[Unset, str]): Emoji символ статуса + title (Union[Unset, str]): Текст статуса + expires_at (Union[None, Unset, datetime.datetime]): Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM- + DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + """ + + emoji: Union[Unset, str] = UNSET + title: Union[Unset, str] = UNSET + expires_at: Union[None, Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emoji = self.emoji + + title = self.title + + expires_at: Union[None, Unset, str] + if isinstance(self.expires_at, Unset): + expires_at = UNSET + elif isinstance(self.expires_at, datetime.datetime): + expires_at = self.expires_at.isoformat() + else: + expires_at = self.expires_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if emoji is not UNSET: + field_dict["emoji"] = emoji + if title is not UNSET: + field_dict["title"] = title + if expires_at is not UNSET: + field_dict["expires_at"] = expires_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + emoji = d.pop("emoji", UNSET) + + title = d.pop("title", UNSET) + + def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + expires_at_type_0 = isoparse(data) + + return expires_at_type_0 + except: # noqa: E722 + pass + return cast(Union[None, Unset, datetime.datetime], data) + + expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) + + status_type_0 = cls( + emoji=emoji, + title=title, + expires_at=expires_at, + ) + + status_type_0.additional_properties = d + return status_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py new file mode 100644 index 0000000..6504540 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py @@ -0,0 +1,77 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Tag") + + +@_attrs_define +class Tag: + """Для получения тега вам необходимо знать его id и указать его в URL запроса. + + Attributes: + id (Union[Unset, int]): Идентификатор тега + name (Union[Unset, str]): Название тега + users_count (Union[Unset, int]): Количество сотрудников, которые имеют этот тег + """ + + id: Union[Unset, int] = UNSET + name: Union[Unset, str] = UNSET + users_count: Union[Unset, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + users_count = self.users_count + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if users_count is not UNSET: + field_dict["users_count"] = users_count + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + users_count = d.pop("users_count", UNSET) + + tag = cls( + id=id, + name=name, + users_count=users_count, + ) + + tag.additional_properties = d + return tag + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed new file mode 100644 index 0000000..1aad327 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py new file mode 100644 index 0000000..b9ed58b --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py @@ -0,0 +1,46 @@ +"""Contains some shared types for properties""" + +from collections.abc import MutableMapping +from http import HTTPStatus +from typing import BinaryIO, Generic, Literal, Optional, TypeVar + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: Optional[str] = None + mime_type: Optional[str] = None + + def to_tuple(self) -> FileJsonType: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: Optional[T] + + +__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/src/generator1/pachca_servis/pyproject.toml b/src/generator1/pachca_servis/pyproject.toml new file mode 100644 index 0000000..29f8de8 --- /dev/null +++ b/src/generator1/pachca_servis/pyproject.toml @@ -0,0 +1,27 @@ +[tool.poetry] +name = "pachca-api-open-api-3-0-client" +version = "3.0.3" +description = "A client library for accessing PachcaAPI - OpenAPI 3.0" +authors = [] +readme = "README.md" +packages = [ + {include = "pachca_api_open_api_3_0_client"}, +] +include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] + + +[tool.poetry.dependencies] +python = "^3.9" +httpx = ">=0.20.0,<0.28.0" +attrs = ">=21.3.0" +python-dateutil = "^2.8.0" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["F", "I", "UP"] diff --git a/src/generator1/script.py b/src/generator1/script.py index 5a140e3..461f1d6 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,3 +1,66 @@ +# import ast +# import os + +# from jinja2 import Environment, FileSystemLoader + + +# def extract_functions_and_imports_from_file(file_path) -> None: +# with open(file_path, "r", encoding="utf-8") as file: +# tree = ast.parse(file.read()) + +# functions = [] +# imports = [] + +# for node in ast.walk(tree): +# if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, +# ast.FunctionDef): +# functions.append(ast.unparse(node)) +# elif isinstance(node, ast.ImportFrom): +# # Убираем пробел после 'from' и обрабатываем импорты +# module = node.module if node.module else '' +# if module.startswith('.'): +# module = module[1:] # Убираем точку в начале +# for alias in node.names: +# if module == 'typing' or module == 'http': +# imports.append(f"from {module} import {alias.name}") +# else: +# imports.append(f"from .{module} import {alias.name}") + +# return functions, imports + + +# def get_all_api_functions_and_imports(api_dir): +# all_functions = [] +# all_imports = [] +# for root, _, files in os.walk(api_dir): +# for file in files: +# if file.endswith(".py"): +# file_path = os.path.join(root, file) +# functions, imports = extract_functions_and_imports_from_file(file_path) +# all_functions.extend(functions) +# all_imports.extend(imports) +# return all_functions, all_imports + + +# api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" +# endpoints, imports = get_all_api_functions_and_imports(api_dir) + +# env = Environment( +# loader=FileSystemLoader('templates') +# ) + +# client_template = env.get_template('client.py.jinja') + +# client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' + +# with open(client_path, mode='w', encoding="utf-8") as file: +# # Объединяем импорты в одну строку +# unique_imports = list(set(imports)) # Убираем дубликаты +# file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл +# file.write(client_template.render(endpoints=endpoints)) + + + import ast import os @@ -12,19 +75,21 @@ def extract_functions_and_imports_from_file(file_path) -> None: imports = [] for node in ast.walk(tree): - if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, - ast.FunctionDef): + if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, ast.FunctionDef): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): - # Убираем пробел после 'from' и обрабатываем импорты - module = node.module if node.module else '' - if module.startswith('.'): - module = module[1:] # Убираем точку в начале + module = node.module if node.module else '.' + # if module.startswith('.'): + # module = module[1:] # Убираем точку в начале for alias in node.names: - if module == 'typing' or module == 'http': - imports.append(f"from {module} import {alias.name}") + if module == 'typing': + imports.append(f"from typing import {alias.name}") + elif module.startswith('models'): + imports.append(f"from .models import {alias.name}") + elif module == 'types': + imports.append(f"from .types import {alias.name}") else: - imports.append(f"from .{module} import {alias.name}") + imports.append(f"from {module} import {alias.name}") return functions, imports @@ -42,7 +107,7 @@ def get_all_api_functions_and_imports(api_dir): return all_functions, all_imports -api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" +api_dir = "./pachca_servis/pachca_api_open_api_3_0_client/api" endpoints, imports = get_all_api_functions_and_imports(api_dir) env = Environment( @@ -51,10 +116,27 @@ def get_all_api_functions_and_imports(api_dir): client_template = env.get_template('client.py.jinja') -client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' +client_path = './pachca_servis/pachca_api_open_api_3_0_client/client.py' with open(client_path, mode='w', encoding="utf-8") as file: - # Объединяем импорты в одну строку - unique_imports = list(set(imports)) # Убираем дубликаты - file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл + unique_imports = list(set(imports)) + models_imports = sorted([model for model in unique_imports if model.startswith('from .models')]) + typing_imports = sorted([model for model in unique_imports if model.startswith('from typing import')]) + types_imports = sorted([model for model in unique_imports if model.startswith('from .types import')]) + other_imports = sorted(list( + set(unique_imports) - set(typing_imports) - set(types_imports) - set(models_imports))) + if models_imports: + models_imports_str = "from .models import (\n " + ",\n ".join( + [model.split('from .models import ')[-1] for model in models_imports]) + "\n)" + file.write(models_imports_str + "\n\n") + if typing_imports: + typing_imports_str = "from typing import (\n " + ",\n ".join( + [model.split('from typing import ')[-1] for model in typing_imports]) + "\n)" + file.write(typing_imports_str + "\n\n") + if types_imports: + types_imports_str = "from .types import (\n " + ",\n ".join( + [model.split('from .types import ')[-1] for model in types_imports]) + "\n)" + file.write(types_imports_str + "\n\n") + if other_imports: + file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints)) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index c11a384..b22718f 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -1,268 +1,7 @@ import datetime -import ssl -from typing import Any, Union, Optional -from attrs import define, field, evolve import httpx - -{% from "macros/client_macros.py.jinja" import httpx_args_docstring %} - -@define -class Client: - """A class for keeping track of data related to the API - -{% macro httpx_args_docstring() %} - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. -{% endmacro %} -{{ httpx_args_docstring() }} - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ -{% macro attributes() %} - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field( - default="https://api.pachca.com/api/shared/v1", - kw_only=True, - alias="base_url" - ) - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) -{% endmacro %}{{ attributes() }} -{% macro builders(self) %} - def with_headers(self, headers: dict[str, str]) -> "{{ self }}": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "{{ self }}": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "{{ self }}": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) -{% endmacro %}{{ builders("Client") }} -{% macro httpx_stuff(name, custom_constructor=None) %} - def set_httpx_client(self, client: httpx.Client) -> "{{ name }}": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - {% if custom_constructor %} - {{ custom_constructor | indent(12) }} - {% endif %} - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "{{ name }}": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "{{ name }}": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - {% if custom_constructor %} - {{ custom_constructor | indent(12) }} - {% endif %} - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "{{ name }}": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) -{% endmacro %}{{ httpx_stuff("Client") }} - -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - {{ httpx_args_docstring() }} - - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field( - default="https://api.pachca.com/api/shared/v1", - kw_only=True, - alias="base_url" - ) - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - +from src.generator1.client_servis import AuthenticatedClient class Pachca: """Главный класс библиотеки.""" From 4abfeae98bb7f8889e243a8984abd4dab4fd5ff1 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 22:32:29 +0300 Subject: [PATCH 109/296] add allOf support to models --- src/generator2/constants.py | 3 +- src/generator2/generate_pydantic_model.py | 1 - src/generator2/openapi_test.yaml | 2270 +++++++++++++++++++++ src/generator2/schema_link_processor.py | 29 +- src/generator2/yaml_processor.py | 2 + 5 files changed, 2302 insertions(+), 3 deletions(-) create mode 100644 src/generator2/openapi_test.yaml diff --git a/src/generator2/constants.py b/src/generator2/constants.py index 1514efb..5802033 100644 --- a/src/generator2/constants.py +++ b/src/generator2/constants.py @@ -1,6 +1,7 @@ import sys -PATH_TO_YAML = './src/generator2/openapi.yaml' +PATH_TO_YAML = './src/generator2/openapi_test.yaml' +# PATH_TO_YAML = './src/generator2/openapi.yaml' PYTHON_TYPES = { 'string': 'str', diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index a3a56ad..3889ca8 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -47,7 +47,6 @@ def look_into_schema(schema: dict) -> None: for property in inner_schema: inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) if 'enum' in inner_body: - print('+'*50, property) enum_properties.append( (property, inner_body.get('type'), inner_body['enum']), ) diff --git a/src/generator2/openapi_test.yaml b/src/generator2/openapi_test.yaml new file mode 100644 index 0000000..4af6b15 --- /dev/null +++ b/src/generator2/openapi_test.yaml @@ -0,0 +1,2270 @@ +openapi: 3.0.3 +info: + title: PachcaAPI - OpenAPI 3.0 + description: Документация к открытому API пачки + version: 3.0.3 +servers: + - url: https://api.pachca.com/api/shared/v1 + +tags: + - name: common methods + description: Everything about common methods + - name: employees + description: Everything about employees + - name: status + description: Everything about + status + - name: tags + description: Everything about + tags + - name: chats and channels + description: Everything about + chats and channels + - name: talk and channel participants + description: Everything about + talk and channel participants + - name: comments + description: Everything about + comments + - name: messages + description: Everything about + messages + - name: reactions to messages + description: Everything about + reactions to messages + - name: reminders + description: Everything about + reminders + +paths: + /custom_properties: + get: + tags: + - common methods + summary: Список дополнительных полей + description: | + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + operationId: getCommonMethods + parameters: + - name: entity_type + in: query + description: Тип сущности + required: true + schema: + type: string + enum: + - User + - Task + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/QueryCommonMethods' + '400': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + /uploads: + post: + tags: + - common methods + summary: Получение подписи и ключа для загрузки файла + description: Возвращает параметры, необходимые для безопасной загрузки файла. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + /direct_url: + post: + tags: + - common methods + summary: Получение URL для загрузки + description: Отправляет запрос для получения URL для безопасной загрузки файла. + operationId: getDirectUrl + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + responses: + '204': + description: Успешный запрос. + /users: + get: + tags: + - employees + summary: получение актуального списка всех сотрудников компании + description: | + Метод для получения актуального списка сотрудников вашей компании. + operationId: getEmployees + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Employee' + /users/{id}: + get: + tags: + - employees + summary: получение информации о сотруднике + description: | + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + operationId: getEmployee + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Employee' + '400': + description: Не удалось найти + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /profile/status: + get: + tags: + - status + summary: получение информации о своем статусе + description: | + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. + operationId: getStatus + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + put: + tags: + - status + summary: новый статус + description: | + Метод для установки себе нового статуса. + operationId: putStatus + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + status: + $ref: '#/components/schemas/Status' + responses: + '201': + description: Объект создан + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + '400': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: + description: Emoji статуса не может содержать значения отличные от Emoji символа + value: + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} + delete: + tags: + - status + summary: удаление своего статуса + description: | + Метод для удаления своего статуса. Параметры запроса отсутствуют. + operationId: delStatus + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствует + content: {} + /group_tags/{id}: + get: + tags: + - tags + summary: Информация о теге + description: | + Параметры запроса отсутствуют + operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + "404": + description: Тег не найден. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Тег не найден. + value: + errors: + - key: "id" + value: "100500" + message: "Не удалось найти тег" + code: "not_found" + /group_tags: + get: + tags: + - tags + summary: Список тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + exclusion: + summary: Недопустимое значение количество возвращаемых сущностей за один запрос + value: + errors: + - key: "per" + value: "51" + message: "Поле имеет недопустимое значение" + code: "exclusion" + /group_tags/{id}/users: + get: + tags: + - tags + operationId: getTagsEmployees + summary: получение актуального списка сотрудников тега + description: | + Метод для получения актуального списка сотрудников тега. + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BaseEmployee' + '400': + description: Поле имеет недопустимое значение + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + /chats: + post: + tags: + - chats and channels + operationId: createChat + summary: Новая беседа или канал + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником.\ + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + chat: + $ref: '#/components/schemas/QueryChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + get: + tags: + - chats and channels + operationId: getChats + summary: Список бесед и каналов + description: Получения списка бесед и каналов по заданным параметрам. + parameters: + - name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + - name: per + in: query + required: false + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + required: false + description: Страница выборки (по умолчанию 1) + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/ErrorsCode' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}: + get: + tags: + - chats and channels + operationId: getChat + summary: Информация о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '404': + description: Запрашиваемый ресурс не существует + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /chats/{id}/members: + post: + tags: + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов пользователей, которые станут участниками + content: + application/json: + schema: + required: + - member_ids + type: object + properties: + member_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + responses: + '201': + description: Пользователи добавлены + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /chats/{id}/group_tags: + post: + tags: + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + responses: + '201': + description: Тег(и) добавлен(ы) + '400': + description: BadRequest + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: 'Выход из беседы или канала' + description: |- + Метод для самостоятельного выхода из беседы или канала. + parameters: + - name: id + in: path + required: true + description: 'Уникальный идентификатор беседы или канала.' + schema: + type: integer + responses: + '200': + description: 'Успешно отписан. Тело ответа отсутствует' + '400': + description: 'Нельзя покинуть персональный чат' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /messages/{id}/thread: + post: + tags: + - comments + summary: Создание нового треда + description: | + Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '200': + description: Тред успешно создан или возвращены данные существующего треда. + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного треда. + chat_id: + type: integer + description: Идентификатор чата треда. + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + '404': + description: Сообщение не найдено. + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + '400': + description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + /messages: + post: + tags: + - messages + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' + example: + message: + entity_type: discussion + entity_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + responses: + '201': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + example: + errors: + - key: entyti_id + value: 1 + message: Не удалось найти + code: not_found + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - key: content + value: null + message: Поле не может быть пустым + code: blank + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - key: entity_type + value: chat + message: Поле имеет недопустимое значение + code: exclusion + get: + tags: + - messages + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + operationId: getListMessage + parameters: + - name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: | + Количество возвращаемых сущностей за один запрос + (по умолчанию 25, максимум 50) + schema: + title: per + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + schema: + title: page + type: integer + default: 1 + responses: + '200': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + errors: + - key: chat_id + value: 1 + message: Не удалось найти + code: not_found + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + examples: + REQUIRED FIELD BLANK: + summary: required fields blank + value: + errors: + - key: chat_id + value: null + message: Поле не может быть пустым + code: blank + INVALID FIELD VALUE: + summary: invalid field value + value: + errors: + - key: chat_id + value: chat + message: Поле имеет недопустимое значение + code: exclusion + /messages/{id}: + get: + tags: + - messages + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + description: Successfull + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + example: + errors: + - key: id + value: 0 + message: Не удалось найти + code: not_found + put: + tags: + - message + operationId: editMessage + summary: Редактирование сообщения + description: Метод для редактирования сообщения или комментария. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/EditMessages' + responses: + '200': + description: Успешно отредактировано + content: + application/json: + schema: + type: object + properties: + data: + type: array + description: Созданное сообщение + items: + $ref: '#/components/schemas/Message' + '400': + description: Нельзя покинуть персональный чат + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + '404': + description: 'Не удалось найти' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ErrorsCode' + /messages/{id}/reactions: + post: + tags: + - reactions to messages + operationId: postMessageReactions + summary: Добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + description: Emoji в строковом формате для добавления реакции. + required: + - code + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + blank_field: + summary: Поле code пустое + value: + error: blank + exclusion: + summary: Недопустимое значение эмодзи + value: + error: exclusion + + "403": + description: Превышение лимитов по реакциям. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки. + examples: + user_limit: + summary: Превышен лимит уникальных реакций пользователя + value: + error: user_limit + message: "Вы можете добавить не более 20 уникальных реакций." + unique_limit: + summary: Превышен лимит уникальных реакций на сообщение + value: + error: unique_limit + message: "Сообщение может содержать не более 30 уникальных реакций." + general_limit: + summary: Превышен общий лимит реакций на сообщение + value: + error: general_limit + message: "Сообщение может содержать не более 1000 реакций." + + "404": + description: Сообщение не найдено. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Сообщение не найдено. + examples: + not_found: + summary: Сообщение не существует + value: + error: not_found + delete: + tags: + - reactions to messages + operationId: deleteMessageReactions + summary: Удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + - name: code + in: query + required: true + description: Emoji, который нужно удалить. + schema: + type: string + responses: + "204": + description: Успешное выполнение запроса, тело ответа отсутствует. + + "400": + description: Ошибка валидации запроса. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок в запросе. + items: + type: object + properties: + key: + type: string + description: Ключ параметра, в котором произошла ошибка. + value: + type: string + description: Значение ключа, вызвавшее ошибку. + message: + type: string + description: Текстовое описание ошибки. + code: + type: string + description: Внутренний код ошибки. + payload: + type: object + description: Дополнительная информация об ошибке. + examples: + blank_field: + summary: Поле code пустое + value: + errors: + - key: "code" + value: "" + message: "Поле не может быть пустым" + code: "blank" + exclusion: + summary: Недопустимое значение эмодзи + value: + errors: + - key: "code" + value: "invalid_emoji" + message: "Поле имеет недопустимое значение" + code: "exclusion" + + "404": + description: Сообщение или реакция не найдены. + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Список ошибок. + items: + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + examples: + not_found: + summary: Сообщение или реакция не найдены + value: + errors: + - key: "reaction" + value: "😊" + message: "Не удалось найти реакцию" + code: "not_found" + get: + tags: + - reactions to messages + operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + parameters: + - name: id + in: path + description: Уникальный идентификатор сообщения + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Список реакций успешно получен. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Reaction' + '404': + description: Сообщение не найдено. + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + '400': + description: Неверный запрос. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + /tasks: + post: + tags: + - reminders + operationId: createTask + summary: 'Метод для создания нового напоминания.' + description: | + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + title: sotrudnik + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + kind: + type: string + description: Тип + content: + type: string + description: Описание + due_at: + type: string + format: date-time + description: Срок выполнения (ISO-8601) + priority: + type: integer + description: Приоритет + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + performer_ids: + type: array + items: + type: integer + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + + '400': + description: Ошибка запроса + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Описание ошибки + +components: + schemas: + BaseEmployee: + type: object + properties: + id: + type: integer + example: 1 + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + role: + type: string + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + allOf: + - $ref: '#/components/schemas/СustomProperties' + bot: + type: boolean + description: | + Тип: пользователь (false) или бот (true) + description: Базовый класс сотрудника. + СustomProperties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + Response: + type: object + properties: + Content-Disposition: + type: string + description: Используемый заголовок + default: attachment + acl: + type: string + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + allOf: + - $ref: '#/components/schemas/Response' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла + DirectResponse: + allOf: + - $ref: '#/components/schemas/Response' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryCommonMethods: + type: object + description: получение списка актульных полей сущности. + properties: + id: + type: integer + example: 1 + description: Название поля + name: + type: string + example: Дата рождения + description: Идентификатор поля + data_type: + type: string + example: number + description: тип поля (string, number, date или link) + NotFound: + description: Объект не найден + type: object + properties: + detail: + description: 'Описание ошибки' + example: "Страница не найдена." + type: string + Errors: + title: Errors + type: array + items: + title: Error + type: object + properties: + key: + title: key + type: string + description: Ключ параметра, в котором произошла ошибка + value: + title: value + type: string + description: Значение ключа, которое вызвало ошибку + message: + title: message + type: string + description: Ошибка текстом, который вы можете вывести пользователю + code: + title: code + type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) + payload: + title: payload + type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + CreateMessage: + type: object + required: + - entity_id + - content + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + files: + title: Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + name: + title: Name + type: string + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + size: + title: Size + type: integer + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false + EditMessages: + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + properties: + content: + type: string + description: Текст сообщения + default: Текст сообщения + files: + type: object + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - 'file' + - 'image' + size: + type: integer + default: 1234 + description: Размер файла в байтах, отображаемый пользователю + buttons: + type: array + description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. + items: + type: array + items: + type: object + properties: + text: + type: string + description: Текст, отображаемый на кнопке пользователю + url: + type: string + description: Ссылка, которая будет открыта по нажатию кнопки + data: + type: string + description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + Message: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + format: date-time + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + description: Размер файла в байтах, отображаемый пользователю + buttons: + title: buttons + allOf: + - $ref: '#/components/schemas/Buttons' + thread: + title: Thread + type: object + nullable: true + default: null + properties: + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + forwarding: + title: Forwarding + type: object + nullable: true + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + Reaction: + type: object + properties: + user_id: + type: integer + description: | + Идентификатор пользователя, оставившего реакцию. + created_at: + type: string + format: date-time + description: | + Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + code: + type: string + description: | + Emoji символ реакции. + BadRequest: + type: object + properties: + error: + type: string + message: + type: string + ErrorsCode: + description: Bad Request + type: object + properties: + key: + type: string + value: + type: string + message: + type: string + code: + type: string + payload: + type: object + Chat: + type: object + description: Беседа или канал + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + name: + type: string + description: Название + example: 🤿 aqua + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + member_ids: + type: array + description: Массив идентификаторов пользователей, участников + items: + type: integer + example: + - 185 + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (false) или открытый (true)' + example: false + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + QueryChat: + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer + securitySchemes: + bearerAuth: + type: http + scheme: bearer +security: + - bearerAuth: [] diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 2ace485..f1fb71a 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -8,8 +8,31 @@ def load_schema(path_to_schema: str) -> dict: def replace_ref_with_schema(schema: dict) -> dict: + # print(schema, '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++') """Заменяет ссылку на схему самой схемой.""" - schema_name = list(schema.keys())[0] + schema_name = next(iter(schema.keys())) + if 'allOf' in schema[schema_name]: + all_inherits = [ingerit for ingerit in schema[schema_name]['allOf'] if '$ref' in ingerit] + all_non_inherits = [ingerit for ingerit in schema[schema_name]['allOf'] if '$ref' not in ingerit] + temp = {} + for inherit in all_inherits: + inheritable = load_schema(inherit['$ref']) + if all_non_inherits: + all_non_inherits[0]['properties'] |= inheritable.get('properties') or inheritable.get('items') + else: + temp |= inheritable.get('properties') or inheritable.get('items') + if all_non_inherits: + schema[schema_name] = all_non_inherits[0] + else: + if 'items' in temp: + schema[schema_name] = temp.get('items') + elif 'properties' in temp: + schema[schema_name] = temp + else: + schema[schema_name] = {'properties': temp} + # schema[schema_name] = {'propertiess': schema[schema_name]} + # print(schema, '---------------------------------------------------------------') + return schema if 'properties' in schema.get(schema_name): current_schema = schema.get(schema_name).get('properties') if 'items' in schema.get(schema_name): @@ -18,6 +41,8 @@ def replace_ref_with_schema(schema: dict) -> dict: if '$ref' in current_schema.get(property): current_schema[property] = load_schema( current_schema.get(property).get('$ref')) + + # print(schema, '---------------------------------------------------------------') return schema @@ -28,6 +53,8 @@ def simple_replace_ref_with_schema(schema: dict) -> dict: key = 'properties' elif 'items' in schema: key = 'items' + elif 'allOf' in schema: + return load_schema(schema['allOf'][0]['$ref']) else: return schema if '$ref' not in schema[key]: diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 6001405..1793520 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -65,6 +65,8 @@ def process_endpoints() -> tuple[list, list]: look_into_schema(replace_ref_with_schema(schema)) print('='*80) + # if operation_id == 'createMessage': + # exit() return path_parameters, query_parameters From 542d2a6bf472e0d96a29d3da4c9fd7f9c984f108 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Mon, 30 Dec 2024 00:35:17 +0500 Subject: [PATCH 110/296] refactoring_3_part_ver1 --- src/openapi.yaml | 1127 +++++++++++++++++++++++----------------------- 1 file changed, 554 insertions(+), 573 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index 4627f01..4586b40 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -1017,40 +1017,44 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -1080,11 +1084,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -1109,41 +1108,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - messages @@ -1233,41 +1234,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1322,18 +1325,25 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - messages @@ -1370,27 +1380,48 @@ paths: items: $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1419,69 +1450,67 @@ paths: responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + - key: string + value: string + message: "Вы можете добавить не более 20 уникальных реакций." + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + - key: string + value: string + message: "Сообщение может содержать не более 30 уникальных реакций." + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + - key: string + value: string + message: "Сообщение может содержать не более 1000 реакций." + code: general_limit + payload: {} delete: tags: - reactions to messages @@ -1505,86 +1534,44 @@ paths: type: string responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - reactions to messages @@ -1626,72 +1613,54 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: 'Метод для создания нового напоминания.' - description: | - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /tasks: + post: + tags: + - reminders + operationId: createTask + summary: 'Метод для создания нового напоминания.' + description: | + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: schema: type: object properties: task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля + $ref: '#/components/schemas/BaseTask' responses: '201': description: Напоминание успешно создано @@ -1701,67 +1670,53 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки - + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: schemas: BaseEmployee: @@ -1829,6 +1784,29 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. Response: type: object properties: @@ -1875,29 +1853,6 @@ components: file: type: string description: Адрес для загрузки файла - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. Status: type: object nullable: true @@ -1931,14 +1886,6 @@ components: type: string example: number description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string Errors: title: Errors type: array @@ -1992,178 +1939,142 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Thread type: object - required: - - entity_id - - content + nullable: true properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id + id: + title: Id type: integer - content: - title: Content - type: string - files: - title: Files - type: array + chat_id: + title: Chat Id + type: integer + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + CreateEditFiles: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array items: type: object - required: - - key - - name - - file_type - - size properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' size: title: Size type: integer - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false + description: Размер файла в байтах, отображаемый пользователю + Files: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array + items: + type: object + properties: + id: + title: Id + type: integer + url: + title: Url + type: string + description: Прямая временная ссылка на скачивание файла EditMessages: type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения files: - type: object + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + BaseMessages: + allOf: + - $ref: '#/components/schemas/EditMessages' + - type: object + required: + - entity_id properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - allOf: - - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object properties: id: title: Id @@ -2171,49 +2082,57 @@ components: chat_id: title: Chat Id type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id + user_id: + title: User Id type: integer + created_at: + title: Created At + type: string + format: date-time + files: + allOf: + - $ref: '#/components/schemas/Files' + title: files + thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + forwarding: + title: Forwarding + type: object nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. Reaction: type: object properties: @@ -2230,27 +2149,6 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object BaseChat: type: object description: Собранный объект параметров создаваемой беседы или канала @@ -2323,6 +2221,89 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: array + items: + type: object + properties: + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + BaseTask: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http From 5e058dd611bea8112bdfec7a556441657cc7e404 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 29 Dec 2024 22:35:20 +0300 Subject: [PATCH 111/296] remove comments --- src/generator2/schema_link_processor.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index f1fb71a..03e0f95 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -8,7 +8,6 @@ def load_schema(path_to_schema: str) -> dict: def replace_ref_with_schema(schema: dict) -> dict: - # print(schema, '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++') """Заменяет ссылку на схему самой схемой.""" schema_name = next(iter(schema.keys())) if 'allOf' in schema[schema_name]: @@ -30,8 +29,6 @@ def replace_ref_with_schema(schema: dict) -> dict: schema[schema_name] = temp else: schema[schema_name] = {'properties': temp} - # schema[schema_name] = {'propertiess': schema[schema_name]} - # print(schema, '---------------------------------------------------------------') return schema if 'properties' in schema.get(schema_name): current_schema = schema.get(schema_name).get('properties') @@ -41,8 +38,6 @@ def replace_ref_with_schema(schema: dict) -> dict: if '$ref' in current_schema.get(property): current_schema[property] = load_schema( current_schema.get(property).get('$ref')) - - # print(schema, '---------------------------------------------------------------') return schema From aa0606d1f4eb8f8420c7e78813be72f631cd045d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 29 Dec 2024 23:53:16 +0300 Subject: [PATCH 112/296] fix script and client_servis --- src/generator1/client_servis.py | 133 +++++++++ .../pachca_api_open_api_3_0_client/client.py | 2 +- src/generator1/script.py | 77 +---- .../templates/client_servis.py.jinja | 267 ++++++++++++++++++ 4 files changed, 415 insertions(+), 64 deletions(-) create mode 100644 src/generator1/templates/client_servis.py.jinja diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index fae0ea2..0219088 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -5,6 +5,139 @@ from attrs import define, evolve, field +@define +class Client: + """A class for keeping track of data related to the API + + + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + @define class AuthenticatedClient: """A Client which has been authenticated for use on secured endpoints diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py index f6cbb07..e98c8e1 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py @@ -70,7 +70,7 @@ import datetime import httpx -from ...client_servis import AuthenticatedClient +from src.generator1.client_servis import AuthenticatedClient class Pachca: """Главный класс библиотеки.""" diff --git a/src/generator1/script.py b/src/generator1/script.py index 461f1d6..92ab09f 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,68 +1,6 @@ -# import ast -# import os - -# from jinja2 import Environment, FileSystemLoader - - -# def extract_functions_and_imports_from_file(file_path) -> None: -# with open(file_path, "r", encoding="utf-8") as file: -# tree = ast.parse(file.read()) - -# functions = [] -# imports = [] - -# for node in ast.walk(tree): -# if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, -# ast.FunctionDef): -# functions.append(ast.unparse(node)) -# elif isinstance(node, ast.ImportFrom): -# # Убираем пробел после 'from' и обрабатываем импорты -# module = node.module if node.module else '' -# if module.startswith('.'): -# module = module[1:] # Убираем точку в начале -# for alias in node.names: -# if module == 'typing' or module == 'http': -# imports.append(f"from {module} import {alias.name}") -# else: -# imports.append(f"from .{module} import {alias.name}") - -# return functions, imports - - -# def get_all_api_functions_and_imports(api_dir): -# all_functions = [] -# all_imports = [] -# for root, _, files in os.walk(api_dir): -# for file in files: -# if file.endswith(".py"): -# file_path = os.path.join(root, file) -# functions, imports = extract_functions_and_imports_from_file(file_path) -# all_functions.extend(functions) -# all_imports.extend(imports) -# return all_functions, all_imports - - -# api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -# endpoints, imports = get_all_api_functions_and_imports(api_dir) - -# env = Environment( -# loader=FileSystemLoader('templates') -# ) - -# client_template = env.get_template('client.py.jinja') - -# client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' - -# with open(client_path, mode='w', encoding="utf-8") as file: -# # Объединяем импорты в одну строку -# unique_imports = list(set(imports)) # Убираем дубликаты -# file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл -# file.write(client_template.render(endpoints=endpoints)) - - - import ast import os +import shutil from jinja2 import Environment, FileSystemLoader @@ -139,4 +77,17 @@ def get_all_api_functions_and_imports(api_dir): file.write(types_imports_str + "\n\n") if other_imports: file.write("\n".join(other_imports) + "\n\n") + # file.write("from .static_client import StaticClient\n\n") file.write(client_template.render(endpoints=endpoints)) + +# cli_servis_template = env.get_template('client_servis.py.jinja') +# cli_servis_path = './pachca_servis/pachca_api_open_api_3_0_client/client_servis.py' + +# with open(cli_servis_path, mode='w', encoding="utf-8") as file: +# file.write(cli_servis_template.render()) +# cli_servis_path = './pachca_servis/pachca_api_open_api_3_0_client/client_servis.py' +# Определяем путь к файлу, который нужно скопировать +source_file = os.path.join(os.path.dirname(__file__), 'generator1', 'client_servis.py') +cli_servis_path = os.path.join(os.path.dirname(__file__), 'pachca_servis', 'pachca_api_open_api_3_0_client', 'client_serv.py') +# import pdb;pdb.set_trace()# Копируем файл +shutil.copy(source_file, cli_servis_path) diff --git a/src/generator1/templates/client_servis.py.jinja b/src/generator1/templates/client_servis.py.jinja new file mode 100644 index 0000000..0219088 --- /dev/null +++ b/src/generator1/templates/client_servis.py.jinja @@ -0,0 +1,267 @@ +import ssl +from typing import Any, Optional, Union + +import httpx +from attrs import define, evolve, field + + +@define +class Client: + """A class for keeping track of data related to the API + + + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(default="https://api.pachca.com/api/shared/v1", kw_only=True, alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) From e882d4f23869f9e1f96acb88beeeaed78d22ffa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 00:43:00 +0300 Subject: [PATCH 113/296] static_metod --- src/generator1/client_servis.py | 274 +------------- .../api/chats_and_channels/create_chat.py | 8 +- .../api/chats_and_channels/get_chat.py | 8 +- .../api/chats_and_channels/get_chats.py | 8 +- .../api/comments/create_thread.py | 8 +- .../api/common_methods/get_common_methods.py | 8 +- .../api/common_methods/get_uploads.py | 8 +- .../api/employees/get_employee.py | 8 +- .../api/employees/get_employees.py | 8 +- .../api/message/edit_message.py | 8 +- .../api/messages/create_message.py | 8 +- .../api/messages/get_list_message.py | 8 +- .../api/messages/get_message.py | 8 +- .../delete_message_reactions.py | 8 +- .../get_message_reactions.py | 8 +- .../post_message_reactions.py | 8 +- .../api/reminders/create_task.py | 8 +- .../api/status/get_status.py | 8 +- .../api/status/put_status.py | 8 +- .../api/tags/get_tag.py | 8 +- .../api/tags/get_tags.py | 8 +- .../api/tags/get_tags_employees.py | 8 +- .../leave_chat.py | 8 +- .../post_members_to_chats.py | 8 +- .../post_tags_to_chats.py | 8 +- .../pachca_api_open_api_3_0_client/client.py | 333 ++++++++++++++++-- .../client_serv.py | 9 + src/generator1/script.py | 2 +- src/generator1/templates/client.py.jinja | 167 ++++++++- .../templates/client_servis.py.jinja | 267 -------------- .../templates/endpoint_module.py.jinja | 8 +- 31 files changed, 665 insertions(+), 587 deletions(-) create mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py delete mode 100644 src/generator1/templates/client_servis.py.jinja diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index 0219088..f1a9b65 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -1,267 +1,9 @@ -import ssl -from typing import Any, Optional, Union - import httpx -from attrs import define, evolve, field - - -@define -class Client: - """A class for keeping track of data related to the API - - - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - - def with_headers(self, headers: dict[str, str]) -> "Client": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "Client": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "Client": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - - def set_httpx_client(self, client: httpx.Client) -> "Client": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "Client": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "Client": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(default="https://api.pachca.com/api/shared/v1", kw_only=True, alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) +from typing import Any, Dict + +class HttpClient: + @staticmethod + async def request(method: str, url: str, **kwargs: Any) -> httpx.Response: + async with httpx.AsyncClient() as client: + response = await client.request(method, url, **kwargs) + return response diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py index 89cdc5a..d3b5bcd 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py @@ -10,6 +10,7 @@ from ...models.create_chat_response_404 import CreateChatResponse404 from ...models.create_chat_response_422 import CreateChatResponse422 from ...types import Response +from .client_serv import HttpClient def _get_kwargs_createChat( @@ -92,6 +93,11 @@ async def createChat( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_createChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py index e134dd6..3e8f64d 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py @@ -7,6 +7,7 @@ from ...models.get_chat_response_200 import GetChatResponse200 from ...models.get_chat_response_404 import GetChatResponse404 from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getChat( @@ -69,6 +70,11 @@ async def getChat( id=id, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py index bebb456..c65f4e2 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py @@ -12,6 +12,7 @@ from ...models.get_chats_response_422 import GetChatsResponse422 from ...models.get_chats_sortid import GetChatsSortid from ...types import UNSET, Response, Unset +from .client_serv import HttpClient def _get_kwargs_getChats( @@ -137,6 +138,11 @@ async def getChats( last_message_at_before=last_message_at_before, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py index eb23656..0de8cc6 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py @@ -8,6 +8,7 @@ from ...models.create_thread_response_200 import CreateThreadResponse200 from ...models.not_found import NotFound from ...types import Response +from .client_serv import HttpClient def _get_kwargs_createThread( @@ -78,6 +79,11 @@ async def createThread( id=id, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_createThread(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py index 7eeb703..41e380b 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py @@ -7,6 +7,7 @@ from ...models.bad_request import BadRequest from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 from ...types import UNSET, Response +from .client_serv import HttpClient def _get_kwargs_getCommonMethods( @@ -80,6 +81,11 @@ async def getCommonMethods( entity_type=entity_type, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getCommonMethods(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py index b5ddcd3..3abeab9 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py @@ -6,6 +6,7 @@ from ... import errors from ...models.file_response import FileResponse from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getUploads( @@ -56,6 +57,11 @@ async def getUploads( kwargs = self._get_kwargs_getUploads() - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getUploads(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py index 5f758db..ded1257 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py @@ -7,6 +7,7 @@ from ...models.get_employee_response_200 import GetEmployeeResponse200 from ...models.not_found import NotFound from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getEmployee( @@ -69,6 +70,11 @@ async def getEmployee( id=id, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getEmployee(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py index d68f825..1cefc69 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py @@ -6,6 +6,7 @@ from ... import errors from ...models.get_employees_response_200 import GetEmployeesResponse200 from ...types import UNSET, Response, Unset +from .client_serv import HttpClient def _get_kwargs_getEmployees( @@ -82,6 +83,11 @@ async def getEmployees( query=query, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getEmployees(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py index 9f4b705..1b571d9 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py @@ -8,6 +8,7 @@ from ...models.edit_message_response_200 import EditMessageResponse200 from ...models.errors_code import ErrorsCode from ...types import Response +from .client_serv import HttpClient def _get_kwargs_editMessage( @@ -99,6 +100,11 @@ async def editMessage( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_editMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py index 89fccb4..cbe2eee 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py @@ -9,6 +9,7 @@ from ...models.create_message_response_201 import CreateMessageResponse201 from ...models.error import Error from ...types import Response +from .client_serv import HttpClient def _get_kwargs_createMessage( @@ -103,6 +104,11 @@ async def createMessage( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_createMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py index 090f093..bdd3107 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py @@ -8,6 +8,7 @@ from ...models.get_list_message_response_200 import GetListMessageResponse200 from ...models.not_found import NotFound from ...types import UNSET, Response, Unset +from .client_serv import HttpClient def _get_kwargs_getListMessage( @@ -101,6 +102,11 @@ async def getListMessage( page=page, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getListMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py index 83f1f22..e5b336e 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py @@ -7,6 +7,7 @@ from ...models.get_message_response_200 import GetMessageResponse200 from ...models.not_found import NotFound from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getMessage( @@ -70,6 +71,11 @@ async def getMessage( id=id, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py index 92090b4..43de16c 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py @@ -7,6 +7,7 @@ from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 from ...types import UNSET, Response +from .client_serv import HttpClient def _get_kwargs_deleteMessageReactions( @@ -87,6 +88,11 @@ async def deleteMessageReactions( code=code, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_deleteMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py index e2721f1..1fef8f1 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py @@ -9,6 +9,7 @@ from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 from ...models.not_found import NotFound from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getMessageReactions( @@ -91,6 +92,11 @@ async def getMessageReactions( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py index 7386098..d1f5daf 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py @@ -9,6 +9,7 @@ from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 from ...types import Response +from .client_serv import HttpClient def _get_kwargs_postMessageReactions( @@ -101,6 +102,11 @@ async def postMessageReactions( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_postMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py index 726cbf8..693d2bf 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py @@ -8,6 +8,7 @@ from ...models.create_task_response_201 import CreateTaskResponse201 from ...models.create_task_response_400 import CreateTaskResponse400 from ...types import Response +from .client_serv import HttpClient def _get_kwargs_createTask( @@ -86,6 +87,11 @@ async def createTask( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_createTask(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py index f0ebcd7..c4612ea 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py @@ -6,6 +6,7 @@ from ... import errors from ...models.get_status_response_200 import GetStatusResponse200 from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getStatus( @@ -56,6 +57,11 @@ async def getStatus( kwargs = self._get_kwargs_getStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getStatus(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py index 1211045..4b2dd51 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py @@ -8,6 +8,7 @@ from ...models.put_status_response_201 import PutStatusResponse201 from ...models.query_status import QueryStatus from ...types import Response +from .client_serv import HttpClient def _get_kwargs_putStatus( @@ -77,6 +78,11 @@ async def putStatus( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_putStatus(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py index 4f0b49f..6e5992b 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py @@ -7,6 +7,7 @@ from ...models.get_tag_response_200 import GetTagResponse200 from ...models.get_tag_response_404 import GetTagResponse404 from ...types import Response +from .client_serv import HttpClient def _get_kwargs_getTag( @@ -68,6 +69,11 @@ async def getTag( id=id, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getTag(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py index 9710704..88f1f16 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py @@ -7,6 +7,7 @@ from ...models.get_tags_response_200 import GetTagsResponse200 from ...models.get_tags_response_400 import GetTagsResponse400 from ...types import UNSET, Response, Unset +from .client_serv import HttpClient def _get_kwargs_getTags( @@ -81,6 +82,11 @@ async def getTags( page=page, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getTags(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py index d259ecd..7d80c24 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py @@ -7,6 +7,7 @@ from ...models.bad_request import BadRequest from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 from ...types import UNSET, Response, Unset +from .client_serv import HttpClient def _get_kwargs_getTagsEmployees( @@ -89,6 +90,11 @@ async def getTagsEmployees( page=page, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_getTagsEmployees(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py index 6ed77e5..1b751a4 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py @@ -6,6 +6,7 @@ from ... import errors from ...models.errors_code import ErrorsCode from ...types import Response +from .client_serv import HttpClient def _get_kwargs_leaveChat( @@ -80,6 +81,11 @@ async def leaveChat( id=id, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_leaveChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py index 5710447..3667224 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py @@ -7,6 +7,7 @@ from ...models.errors_code import ErrorsCode from ...models.post_members_to_chats_body import PostMembersToChatsBody from ...types import Response +from .client_serv import HttpClient def _get_kwargs_postMembersToChats( @@ -84,6 +85,11 @@ async def postMembersToChats( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_postMembersToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py index 1d90b2c..11767db 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py @@ -7,6 +7,7 @@ from ...models.errors_code import ErrorsCode from ...models.post_tags_to_chats_body import PostTagsToChatsBody from ...types import Response +from .client_serv import HttpClient def _get_kwargs_postTagsToChats( @@ -84,6 +85,11 @@ async def postTagsToChats( body=body, ) - response = await self.client.get_async_httpx_client().request(**kwargs) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + # ) + response = await HttpClient.request( + method=kwargs["method"], url=kwargs["url"], **kwargs + ) # Используйте статичный метод return self._build_response_postTagsToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py index e98c8e1..7274bec 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py @@ -65,12 +65,295 @@ ) from . import errors +from .client_serv import HttpClient from http import HTTPStatus import datetime import httpx -from src.generator1.client_servis import AuthenticatedClient +from .client_serv import HttpClient +import ssl +from typing import Any, Union, Optional + +from attrs import define, field, evolve + + +@define +class Client: + """A class for keeping track of data related to the API + + + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + class Pachca: """Главный класс библиотеки.""" @@ -127,7 +410,7 @@ async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatRes Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] """ kwargs = self._get_kwargs_createChat(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_createChat(response=response).parsed def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: @@ -166,7 +449,7 @@ async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatRe Union[GetChatResponse200, GetChatResponse404] """ kwargs = self._get_kwargs_getChat(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getChat(response=response).parsed def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: @@ -236,7 +519,7 @@ async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DES Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] """ kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getChats(response=response).parsed def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: @@ -278,7 +561,7 @@ async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThread Union[BadRequest, CreateThreadResponse200, NotFound] """ kwargs = self._get_kwargs_createThread(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_createThread(response=response).parsed def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: @@ -320,7 +603,7 @@ async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, Union[BadRequest, GetCommonMethodsResponse200] """ kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getCommonMethods(response=response).parsed def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: @@ -371,7 +654,7 @@ async def getUploads(self) -> Optional[FileResponse]: FileResponse """ kwargs = self._get_kwargs_getUploads() - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getUploads(response=response).parsed def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: @@ -410,7 +693,7 @@ async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, N Union[GetEmployeeResponse200, NotFound] """ kwargs = self._get_kwargs_getEmployee(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getEmployee(response=response).parsed def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: @@ -452,7 +735,7 @@ async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]= GetEmployeesResponse200 """ kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getEmployees(response=response).parsed def _get_kwargs_editMessage(self, id: int, body: EditMessageBody) -> dict[str, Any]: @@ -507,7 +790,7 @@ async def editMessage(self, id: int, body: EditMessageBody) -> Optional[Union[Ed Union[EditMessageResponse200, list['ErrorsCode']] """ kwargs = self._get_kwargs_editMessage(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_editMessage(response=response).parsed def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: @@ -569,7 +852,7 @@ async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequ Union[BadRequest, CreateMessageResponse201, list['Error']] """ kwargs = self._get_kwargs_createMessage(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_createMessage(response=response).parsed def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: @@ -622,7 +905,7 @@ async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Un Union[BadRequest, GetListMessageResponse200, NotFound] """ kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getListMessage(response=response).parsed def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: @@ -662,7 +945,7 @@ async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, Not Union[GetMessageResponse200, NotFound] """ kwargs = self._get_kwargs_getMessage(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getMessage(response=response).parsed def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: @@ -708,7 +991,7 @@ async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] """ kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_deleteMessageReactions(response=response).parsed def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: @@ -756,7 +1039,7 @@ async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> O Union[BadRequest, GetMessageReactionsResponse200, NotFound] """ kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getMessageReactions(response=response).parsed def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: @@ -808,7 +1091,7 @@ async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] """ kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_postMessageReactions(response=response).parsed def _get_kwargs_createTask(self, body: CreateTaskBody) -> dict[str, Any]: @@ -856,7 +1139,7 @@ async def createTask(self, body: CreateTaskBody) -> Optional[Union[CreateTaskRes Union[CreateTaskResponse201, CreateTaskResponse400] """ kwargs = self._get_kwargs_createTask(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_createTask(response=response).parsed def _get_kwargs_delStatus(self) -> dict[str, Any]: @@ -903,7 +1186,7 @@ async def getStatus(self) -> Optional[GetStatusResponse200]: GetStatusResponse200 """ kwargs = self._get_kwargs_getStatus() - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getStatus(response=response).parsed def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: @@ -946,7 +1229,7 @@ async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutSt Union[BadRequest, PutStatusResponse201] """ kwargs = self._get_kwargs_putStatus(body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_putStatus(response=response).parsed def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: @@ -984,7 +1267,7 @@ async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagRespo Union[GetTagResponse200, GetTagResponse404] """ kwargs = self._get_kwargs_getTag(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getTag(response=response).parsed def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: @@ -1027,7 +1310,7 @@ async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Union[GetTagsResponse200, GetTagsResponse400] """ kwargs = self._get_kwargs_getTags(per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getTags(response=response).parsed def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: @@ -1071,7 +1354,7 @@ async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union Union[BadRequest, GetTagsEmployeesResponse200] """ kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getTagsEmployees(response=response).parsed def _get_kwargs_leaveChat(self, id: int) -> dict[str, Any]: @@ -1120,7 +1403,7 @@ async def leaveChat(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_leaveChat(id=id) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_leaveChat(response=response).parsed def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: @@ -1168,7 +1451,7 @@ async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Opt Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_postMembersToChats(response=response).parsed def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: @@ -1216,7 +1499,7 @@ async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[ Union[Any, list['ErrorsCode']] """ kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) - response = await self.client.get_async_httpx_client().request(**kwargs) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_postTagsToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py new file mode 100644 index 0000000..f1a9b65 --- /dev/null +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py @@ -0,0 +1,9 @@ +import httpx +from typing import Any, Dict + +class HttpClient: + @staticmethod + async def request(method: str, url: str, **kwargs: Any) -> httpx.Response: + async with httpx.AsyncClient() as client: + response = await client.request(method, url, **kwargs) + return response diff --git a/src/generator1/script.py b/src/generator1/script.py index 92ab09f..7cec085 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -87,7 +87,7 @@ def get_all_api_functions_and_imports(api_dir): # file.write(cli_servis_template.render()) # cli_servis_path = './pachca_servis/pachca_api_open_api_3_0_client/client_servis.py' # Определяем путь к файлу, который нужно скопировать -source_file = os.path.join(os.path.dirname(__file__), 'generator1', 'client_servis.py') +source_file = os.path.join(os.path.dirname(__file__), '..', 'generator1', 'client_servis.py') cli_servis_path = os.path.join(os.path.dirname(__file__), 'pachca_servis', 'pachca_api_open_api_3_0_client', 'client_serv.py') # import pdb;pdb.set_trace()# Копируем файл shutil.copy(source_file, cli_servis_path) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index b22718f..d3a5fe9 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -1,7 +1,172 @@ import datetime import httpx -from src.generator1.client_servis import AuthenticatedClient +from .client_serv import HttpClient +import ssl +from typing import Any, Union, Optional + +from attrs import define, field, evolve + + +@define +class Client: + """A class for keeping track of data related to the API + +{% macro httpx_args_docstring() %} + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. +{% endmacro %} +{{ httpx_args_docstring() }} + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ +{% macro attributes() %} + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) +{% endmacro %}{{ attributes() }} +{% macro builders(self) %} + def with_headers(self, headers: dict[str, str]) -> "{{ self }}": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "{{ self }}": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "{{ self }}": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) +{% endmacro %}{{ builders("Client") }} +{% macro httpx_stuff(name, custom_constructor=None) %} + def set_httpx_client(self, client: httpx.Client) -> "{{ name }}": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + {% if custom_constructor %} + {{ custom_constructor | indent(12) }} + {% endif %} + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "{{ name }}": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "{{ name }}": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + {% if custom_constructor %} + {{ custom_constructor | indent(12) }} + {% endif %} + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "{{ name }}": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) +{% endmacro %}{{ httpx_stuff("Client") }} + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + +{{ httpx_args_docstring() }} + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + +{{ attributes() }} + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + +{{ builders("AuthenticatedClient") }} +{{ httpx_stuff("AuthenticatedClient", "self._headers[self.auth_header_name] = f\"{self.prefix} {self.token}\" if self.prefix else self.token") }} class Pachca: """Главный класс библиотеки.""" diff --git a/src/generator1/templates/client_servis.py.jinja b/src/generator1/templates/client_servis.py.jinja deleted file mode 100644 index 0219088..0000000 --- a/src/generator1/templates/client_servis.py.jinja +++ /dev/null @@ -1,267 +0,0 @@ -import ssl -from typing import Any, Optional, Union - -import httpx -from attrs import define, evolve, field - - -@define -class Client: - """A class for keeping track of data related to the API - - - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - - def with_headers(self, headers: dict[str, str]) -> "Client": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "Client": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "Client": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - - def set_httpx_client(self, client: httpx.Client) -> "Client": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "Client": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "Client": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(default="https://api.pachca.com/api/shared/v1", kw_only=True, alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index 81a1c3c..2885e08 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -6,6 +6,7 @@ import httpx from ...client import AuthenticatedClient, Client from ...types import Response, UNSET from ... import errors +from .client_serv import HttpClient {% for relative in endpoint.relative_imports | sort %} {{ relative }} @@ -109,9 +110,10 @@ async def {{ endpoint.name }}(self, {{ kwargs(endpoint, include_client=False) }} ) - response = await self.client.get_async_httpx_client().request( - **kwargs - ) + # response = await self.client.get_async_httpx_client().request( + # **kwargs + #) + response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) # Используйте статичный метод return self._build_response_{{ endpoint.name }}( response=response).parsed From 2e061d7077e27251a8ce9a8c4d22ea1beece21ee Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 30 Dec 2024 01:20:31 +0300 Subject: [PATCH 114/296] added base_url throught parse yaml #2 --- src/generator1/script.py | 94 ------------------------ src/generator1/templates/client.py.jinja | 18 ++--- 2 files changed, 8 insertions(+), 104 deletions(-) diff --git a/src/generator1/script.py b/src/generator1/script.py index 3b71cab..01da345 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,97 +1,3 @@ -# import ast -# import os -# import subprocess - -# import yaml -# from jinja2 import Environment, FileSystemLoader - - -# def extract_functions_and_imports_from_file(file_path) -> None: -# with open(file_path, "r", encoding="utf-8") as file: -# tree = ast.parse(file.read()) - -# functions = [] -# imports = [] - -# for node in ast.walk(tree): -# if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, -# ast.FunctionDef): -# functions.append(ast.unparse(node)) -# elif isinstance(node, ast.ImportFrom): -# # Убираем пробел после 'from' и обрабатываем импорты -# module = node.module if node.module else '' -# if module.startswith('.'): -# module = module[1:] # Убираем точку в начале -# for alias in node.names: -# if module == 'typing' or module == 'http': -# imports.append(f"from {module} import {alias.name}") -# else: -# imports.append(f"from .{module} import {alias.name}") - -# return functions, imports - - -# def get_all_api_functions_and_imports(api_dir): -# all_functions = [] -# all_imports = [] -# for root, _, files in os.walk(api_dir): -# for file in files: -# if file.endswith(".py"): -# file_path = os.path.join(root, file) -# functions, imports = extract_functions_and_imports_from_file(file_path) -# all_functions.extend(functions) -# all_imports.extend(imports) -# return all_functions, all_imports - - -# def create_modified_openapi_yaml(input_path, output_path): -# with open(input_path, "r", encoding="utf-8") as file: -# openapi_data = yaml.safe_load(file) -# base_url = openapi_data.get("servers", [{}])[0].get("url") -# openapi_data["x-base-url"] = base_url - -# with open(output_path, "w", encoding="utf-8") as file: -# yaml.dump(openapi_data, file) - -# return base_url - - -# def generate_client(openapi_path, templates_path): -# command = [ -# "openapi-python-client", -# "generate", -# "--path", openapi_path, -# "--custom-template-path", templates_path, -# "--overwrite" -# ] -# subprocess.run(command, check=True) - - -# def process_generated_client(api_dir, client_template_path, client_output_path, base_url): -# endpoints, imports = get_all_api_functions_and_imports(api_dir) - -# env = Environment(loader=FileSystemLoader('templates')) -# client_template = env.get_template(client_template_path) - -# with open(client_output_path, mode='w', encoding="utf-8") as file: -# # Объединяем импорты в одну строку -# unique_imports = list(set(imports)) # Убираем дубликаты -# file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл -# file.write(client_template.render(endpoints=endpoints, base_url=base_url)) - - -# openapi_input_path = "openapi.yaml" -# openapi_modified_path = "openapi_modified.yaml" -# templates_path = "./templates" -# api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -# client_template_name = "client.py.jinja" -# client_output_path = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" - -# # Выполнение шагов -# base_url = create_modified_openapi_yaml(openapi_input_path, openapi_modified_path) -# generate_client(openapi_modified_path, templates_path) -# process_generated_client(api_dir, client_template_name, client_output_path, base_url) - import ast import os diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index e35a6ec..643bfc6 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -157,11 +157,6 @@ class AuthenticatedClient: """ raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field( - default="{{ base_url }}", - kw_only=True, - alias="base_url" - ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") @@ -172,6 +167,7 @@ class AuthenticatedClient: _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) token: str + base_url: str prefix: str = "Bearer" auth_header_name: str = "Authorization" @@ -212,7 +208,7 @@ class AuthenticatedClient: if self._client is None: self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token self._client = httpx.Client( - base_url=self._base_url, + base_url=self.base_url, cookies=self._cookies, headers=self._headers, timeout=self._timeout, @@ -244,7 +240,7 @@ class AuthenticatedClient: if self._async_client is None: self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token self._async_client = httpx.AsyncClient( - base_url=self._base_url, + base_url=self.base_url, cookies=self._cookies, headers=self._headers, timeout=self._timeout, @@ -267,9 +263,11 @@ class AuthenticatedClient: class Pachca: """Главный класс библиотеки.""" - def __init__(self, token): - self.client = AuthenticatedClient(token=token) - self.base_url = '{{ base_url }}' + def __init__(self, token, base_url='{{ base_url }}'): + self.client = AuthenticatedClient( + token=token, + base_url=base_url + ) {% if endpoints %} {% for endpoint in endpoints %} {{ endpoint | indent(4, first=Fasle) }} From 5f17ebda804e698a5ac307028a01bab99a32e246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 13:37:35 +0300 Subject: [PATCH 115/296] fix query --- src/generator1/pachca.py | 1 + .../pachca_api_open_api_3_0_client/client.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 5eed0a1..5399a3e 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -10,6 +10,7 @@ pachca = Pachca( token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', + base_url = 'https://api.pachca.com/api/shared/v1' ) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py index 7274bec..d55c8ea 100644 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py +++ b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py @@ -358,8 +358,8 @@ async def __aexit__(self, *args: Any, **kwargs: Any) -> None: class Pachca: """Главный класс библиотеки.""" - def __init__(self, token): - self.client = AuthenticatedClient(token=token) + def __init__(self, base_url, token): + self.client = AuthenticatedClient(base_url=base_url, token=token) @@ -410,7 +410,11 @@ async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatRes Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] """ kwargs = self._get_kwargs_createChat(body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) + base_url = self.client._base_url # Получаем базовый URL из клиента + full_url = f"{base_url}{kwargs['url']}" # Формируем полный URL + kwargs['url'] = full_url # Обновляем URL в kwargs + response = await HttpClient.request(**kwargs) + # response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_createChat(response=response).parsed def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: @@ -735,7 +739,14 @@ async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]= GetEmployeesResponse200 """ kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) + # Добавляем базовый URL к запросу + base_url = self.client._base_url # Получаем базовый URL из клиента + full_url = f"{base_url}{kwargs['url']}" # Формируем полный URL + kwargs['url'] = full_url # Обновляем URL в kwargs + import pdb;pdb.set_trace() + response = await HttpClient.request(**kwargs) + + # response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) return self._build_response_getEmployees(response=response).parsed def _get_kwargs_editMessage(self, id: int, body: EditMessageBody) -> dict[str, Any]: From 1e123fa64ff28bdfcf75cc587b2d8a86e4e0d13f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 14:26:26 +0300 Subject: [PATCH 116/296] fix --- src/generator1/pachca.py | 13 +- src/generator1/pachca_servis/.gitignore | 23 - src/generator1/pachca_servis/README.md | 124 -- .../__init__.py | 8 - .../api/__init__.py | 1 - .../api/chats_and_channels/__init__.py | 0 .../api/chats_and_channels/create_chat.py | 103 -- .../api/chats_and_channels/get_chat.py | 80 - .../api/chats_and_channels/get_chats.py | 148 -- .../api/comments/__init__.py | 0 .../api/comments/create_thread.py | 89 - .../api/common_methods/__init__.py | 0 .../api/common_methods/get_common_methods.py | 91 - .../api/common_methods/get_direct_url.py | 45 - .../api/common_methods/get_uploads.py | 67 - .../api/employees/__init__.py | 0 .../api/employees/get_employee.py | 80 - .../api/employees/get_employees.py | 93 - .../api/message/__init__.py | 0 .../api/message/edit_message.py | 110 -- .../api/messages/__init__.py | 0 .../api/messages/create_message.py | 114 -- .../api/messages/get_list_message.py | 112 -- .../api/messages/get_message.py | 81 - .../api/reactions_to_messages/__init__.py | 0 .../delete_message_reactions.py | 98 -- .../get_message_reactions.py | 102 -- .../post_message_reactions.py | 112 -- .../api/reminders/__init__.py | 0 .../api/reminders/create_task.py | 97 -- .../api/status/__init__.py | 0 .../api/status/del_status.py | 36 - .../api/status/get_status.py | 67 - .../api/status/put_status.py | 88 - .../api/tags/__init__.py | 0 .../api/tags/get_tag.py | 79 - .../api/tags/get_tags.py | 92 - .../api/tags/get_tags_employees.py | 100 -- .../talk_and_channel_participants/__init__.py | 0 .../leave_chat.py | 91 - .../post_members_to_chats.py | 95 -- .../post_tags_to_chats.py | 95 -- .../pachca_api_open_api_3_0_client/client.py | 1517 ----------------- .../client_serv.py | 9 - .../pachca_api_open_api_3_0_client/errors.py | 16 - .../models/__init__.py | 189 -- .../models/bad_request.py | 67 - .../models/base_employee.py | 186 -- .../base_employee_custom_properties_item.py | 85 - .../models/button.py | 78 - .../models/chat.py | 162 -- .../models/create_chat_body.py | 71 - .../models/create_chat_response_201.py | 71 - .../models/create_chat_response_400.py | 74 - .../models/create_chat_response_404.py | 74 - .../models/create_chat_response_422.py | 74 - .../models/create_message.py | 178 -- .../models/create_message_body.py | 71 - .../models/create_message_entity_type.py | 10 - .../models/create_message_files_item.py | 84 - .../create_message_files_item_file_type.py | 9 - .../models/create_message_response_201.py | 71 - .../models/create_task_body.py | 71 - .../models/create_task_body_task.py | 123 -- ...e_task_body_task_custom_properties_item.py | 67 - .../models/create_task_response_201.py | 71 - .../models/create_task_response_201_data.py | 179 -- ...esponse_201_data_custom_properties_item.py | 85 - .../models/create_task_response_400.py | 58 - .../models/create_thread_response_200.py | 71 - .../models/create_thread_response_200_data.py | 104 -- .../delete_message_reactions_response_400.py | 76 - ...sage_reactions_response_400_errors_item.py | 111 -- ...ctions_response_400_errors_item_payload.py | 43 - .../delete_message_reactions_response_404.py | 76 - ...sage_reactions_response_404_errors_item.py | 111 -- ...ctions_response_404_errors_item_payload.py | 43 - .../models/direct_response.py | 195 --- .../models/edit_message_body.py | 72 - .../models/edit_message_response_200.py | 74 - .../models/edit_messages.py | 113 -- .../models/edit_messages_buttons_item_item.py | 76 - .../models/edit_messages_files.py | 95 -- .../models/edit_messages_files_file_type.py | 9 - .../models/employee.py | 275 --- .../models/error.py | 107 -- .../models/error_payload.py | 43 - .../models/errors_code.py | 108 -- .../models/errors_code_payload.py | 43 - .../models/file_response.py | 130 -- .../models/get_chat_response_200.py | 71 - .../models/get_chat_response_404.py | 74 - .../models/get_chats_availability.py | 9 - .../models/get_chats_response_200.py | 74 - .../models/get_chats_response_400.py | 71 - .../models/get_chats_response_404.py | 74 - .../models/get_chats_response_422.py | 74 - .../models/get_chats_sortid.py | 9 - .../models/get_common_methods_response_200.py | 74 - .../models/get_employee_response_200.py | 71 - .../models/get_employees_response_200.py | 74 - .../models/get_list_message_response_200.py | 74 - .../models/get_message_reactions_body.py | 68 - .../get_message_reactions_response_200.py | 74 - .../models/get_message_response_200.py | 71 - .../models/get_status_response_200.py | 88 - .../models/get_tag_response_200.py | 71 - .../models/get_tag_response_404.py | 74 - .../get_tag_response_404_errors_item.py | 107 -- ...et_tag_response_404_errors_item_payload.py | 43 - .../models/get_tags_employees_response_200.py | 74 - .../models/get_tags_response_200.py | 74 - .../models/get_tags_response_400.py | 74 - .../get_tags_response_400_errors_item.py | 107 -- ...t_tags_response_400_errors_item_payload.py | 43 - .../models/message.py | 272 --- .../models/message_entity_type.py | 10 - .../models/message_files_item.py | 104 -- .../models/message_files_item_file_type.py | 9 - .../models/message_forwarding.py | 153 -- .../models/message_thread.py | 67 - .../models/not_found.py | 59 - .../models/post_members_to_chats_body.py | 69 - .../models/post_message_reactions_body.py | 58 - .../post_message_reactions_response_400.py | 58 - .../post_message_reactions_response_403.py | 58 - .../post_message_reactions_response_404.py | 58 - .../models/post_tags_to_chats_body.py | 58 - .../models/put_status_response_201.py | 88 - .../models/query_chat.py | 91 - .../models/query_common_methods.py | 77 - .../models/query_status.py | 71 - .../models/query_status_status.py | 102 -- .../models/reaction.py | 86 - .../models/status_type_0.py | 101 -- .../models/tag.py | 77 - .../pachca_api_open_api_3_0_client/py.typed | 1 - .../pachca_api_open_api_3_0_client/types.py | 46 - src/generator1/pachca_servis/pyproject.toml | 27 - src/generator1/script.py | 8 +- 140 files changed, 13 insertions(+), 11771 deletions(-) delete mode 100644 src/generator1/pachca_servis/.gitignore delete mode 100644 src/generator1/pachca_servis/README.md delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed delete mode 100644 src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py delete mode 100644 src/generator1/pachca_servis/pyproject.toml diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 5399a3e..a065d62 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -1,8 +1,14 @@ +# pachca = Pachca( +# token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', +# base_url = 'https://api.pachca.com/api/shared/v1' +# ) import asyncio -from pachca_servis.pachca_api_open_api_3_0_client.client import Pachca -from pachca_servis.pachca_api_open_api_3_0_client.models.create_chat_body import CreateChatBody -from pachca_servis.pachca_api_open_api_3_0_client.models.query_chat import QueryChat +from pachca_api_open_api_3_0_client.client import Pachca +from pachca_api_open_api_3_0_client.models.create_chat_body import ( + CreateChatBody, +) +from pachca_api_open_api_3_0_client.models.query_chat import QueryChat query_chat = QueryChat(name='test') chat_body = CreateChatBody(chat=query_chat) @@ -10,7 +16,6 @@ pachca = Pachca( token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', - base_url = 'https://api.pachca.com/api/shared/v1' ) diff --git a/src/generator1/pachca_servis/.gitignore b/src/generator1/pachca_servis/.gitignore deleted file mode 100644 index 79a2c3d..0000000 --- a/src/generator1/pachca_servis/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -__pycache__/ -build/ -dist/ -*.egg-info/ -.pytest_cache/ - -# pyenv -.python-version - -# Environments -.env -.venv - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# JetBrains -.idea/ - -/coverage.xml -/.coverage diff --git a/src/generator1/pachca_servis/README.md b/src/generator1/pachca_servis/README.md deleted file mode 100644 index 3bb71ab..0000000 --- a/src/generator1/pachca_servis/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# pachca-api-open-api-3-0-client -A client library for accessing PachcaAPI - OpenAPI 3.0 - -## Usage -First, create a client: - -```python -from pachca_api_open_api_3_0_client import Client - -client = Client(base_url="https://api.example.com") -``` - -If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: - -```python -from pachca_api_open_api_3_0_client import AuthenticatedClient - -client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") -``` - -Now call your endpoint and use your models: - -```python -from pachca_api_open_api_3_0_client.models import MyDataModel -from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model -from pachca_api_open_api_3_0_client.types import Response - -with client as client: - my_data: MyDataModel = get_my_data_model.sync(client=client) - # or if you need more info (e.g. status_code) - response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) -``` - -Or do the same thing with an async version: - -```python -from pachca_api_open_api_3_0_client.models import MyDataModel -from pachca_api_open_api_3_0_client.api.my_tag import get_my_data_model -from pachca_api_open_api_3_0_client.types import Response - -async with client as client: - my_data: MyDataModel = await get_my_data_model.asyncio(client=client) - response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) -``` - -By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. - -```python -client = AuthenticatedClient( - base_url="https://internal_api.example.com", - token="SuperSecretToken", - verify_ssl="/path/to/certificate_bundle.pem", -) -``` - -You can also disable certificate validation altogether, but beware that **this is a security risk**. - -```python -client = AuthenticatedClient( - base_url="https://internal_api.example.com", - token="SuperSecretToken", - verify_ssl=False -) -``` - -Things to know: -1. Every path/method combo becomes a Python module with four functions: - 1. `sync`: Blocking request that returns parsed data (if successful) or `None` - 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. - 1. `asyncio`: Like `sync` but async instead of blocking - 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking - -1. All path/query params, and bodies become method arguments. -1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) -1. Any endpoint which did not have a tag will be in `pachca_api_open_api_3_0_client.api.default` - -## Advanced customizations - -There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): - -```python -from pachca_api_open_api_3_0_client import Client - -def log_request(request): - print(f"Request event hook: {request.method} {request.url} - Waiting for response") - -def log_response(response): - request = response.request - print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") - -client = Client( - base_url="https://api.example.com", - httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, -) - -# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() -``` - -You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): - -```python -import httpx -from pachca_api_open_api_3_0_client import Client - -client = Client( - base_url="https://api.example.com", -) -# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. -client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) -``` - -## Building / publishing this package -This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: -1. Update the metadata in pyproject.toml (e.g. authors, version) -1. If you're using a private repository, configure it with Poetry - 1. `poetry config repositories. ` - 1. `poetry config http-basic. ` -1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` - -If you want to install this client into another project without publishing it (e.g. for development) then: -1. If that project **is using Poetry**, you can simply do `poetry add ` from that project -1. If that project is not using Poetry: - 1. Build a wheel with `poetry build -f wheel` - 1. Install that wheel from the other project `pip install ` diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py deleted file mode 100644 index 3a6c9f0..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""A client library for accessing PachcaAPI - OpenAPI 3.0""" - -from .client import AuthenticatedClient, Client - -__all__ = ( - "AuthenticatedClient", - "Client", -) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py deleted file mode 100644 index 81f9fa2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Contains methods for accessing the API""" diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py deleted file mode 100644 index d3b5bcd..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/create_chat.py +++ /dev/null @@ -1,103 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.create_chat_body import CreateChatBody -from ...models.create_chat_response_201 import CreateChatResponse201 -from ...models.create_chat_response_400 import CreateChatResponse400 -from ...models.create_chat_response_404 import CreateChatResponse404 -from ...models.create_chat_response_422 import CreateChatResponse422 -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_createChat( - self, - body: CreateChatBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/chats", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_createChat( - self, response: httpx.Response -) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) - - return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createChat( - self, response: httpx.Response -) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createChat(response=response), - ) - - -async def createChat( - self, - body: CreateChatBody, -) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - r""" Новая беседа или канал - - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ - - Args: - body (CreateChatBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - - kwargs = self._get_kwargs_createChat( - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_createChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py deleted file mode 100644 index 3e8f64d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chat.py +++ /dev/null @@ -1,80 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_chat_response_200 import GetChatResponse200 -from ...models.get_chat_response_404 import GetChatResponse404 -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getChat( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/chats/{id}", - } - - return _kwargs - - -def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getChat(response=response), - ) - - -async def getChat( - self, - id: int, -) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале - - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatResponse200, GetChatResponse404] - """ - - kwargs = self._get_kwargs_getChat( - id=id, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py deleted file mode 100644 index c65f4e2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/chats_and_channels/get_chats.py +++ /dev/null @@ -1,148 +0,0 @@ -import datetime -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_chats_availability import GetChatsAvailability -from ...models.get_chats_response_200 import GetChatsResponse200 -from ...models.get_chats_response_400 import GetChatsResponse400 -from ...models.get_chats_response_404 import GetChatsResponse404 -from ...models.get_chats_response_422 import GetChatsResponse422 -from ...models.get_chats_sortid import GetChatsSortid -from ...types import UNSET, Response, Unset -from .client_serv import HttpClient - - -def _get_kwargs_getChats( - self, - sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, - availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, - last_message_at_after: Union[Unset, datetime.datetime] = UNSET, - last_message_at_before: Union[Unset, datetime.datetime] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - - params["sort[id]"] = json_sortid - - params["per"] = per - - params["page"] = page - - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - - params["availability"] = json_availability - - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params["last_message_at_after"] = json_last_message_at_after - - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params["last_message_at_before"] = json_last_message_at_before - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/chats", - "params": params, - } - - return _kwargs - - -def _parse_response_getChats( - self, response: httpx.Response -) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getChats( - self, response: httpx.Response -) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getChats(response=response), - ) - - -async def getChats( - self, - sortid: Union[Unset, GetChatsSortid] = GetChatsSortid.DESC, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, - availability: Union[Unset, GetChatsAvailability] = GetChatsAvailability.IS_MEMBER, - last_message_at_after: Union[Unset, datetime.datetime] = UNSET, - last_message_at_before: Union[Unset, datetime.datetime] = UNSET, -) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - - kwargs = self._get_kwargs_getChats( - sortid=sortid, - per=per, - page=page, - availability=availability, - last_message_at_after=last_message_at_after, - last_message_at_before=last_message_at_before, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py deleted file mode 100644 index 0de8cc6..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/comments/create_thread.py +++ /dev/null @@ -1,89 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.create_thread_response_200 import CreateThreadResponse200 -from ...models.not_found import NotFound -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_createThread( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/messages/{id}/thread", - } - - return _kwargs - - -def _parse_response_createThread( - self, response: httpx.Response -) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createThread( - self, response: httpx.Response -) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createThread(response=response), - ) - - -async def createThread( - self, - id: int, -) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - - kwargs = self._get_kwargs_createThread( - id=id, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_createThread(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py deleted file mode 100644 index 41e380b..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_common_methods.py +++ /dev/null @@ -1,91 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_common_methods_response_200 import GetCommonMethodsResponse200 -from ...types import UNSET, Response -from .client_serv import HttpClient - - -def _get_kwargs_getCommonMethods( - self, - entity_type: str, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["entity_type"] = entity_type - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/custom_properties", - "params": params, - } - - return _kwargs - - -def _parse_response_getCommonMethods( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getCommonMethods( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getCommonMethods(response=response), - ) - - -async def getCommonMethods( - self, - entity_type: str, -) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetCommonMethodsResponse200] - """ - - kwargs = self._get_kwargs_getCommonMethods( - entity_type=entity_type, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getCommonMethods(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py deleted file mode 100644 index 49b24c6..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_direct_url.py +++ /dev/null @@ -1,45 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...models.direct_response import DirectResponse -from ...types import Response - - -def _get_kwargs_getDirectUrl( - self, - body: DirectResponse, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/direct_url", - } - - _body = body.to_multipart() - - _kwargs["files"] = _body - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getDirectUrl(response=response), - ) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py deleted file mode 100644 index 3abeab9..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/common_methods/get_uploads.py +++ /dev/null @@ -1,67 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...models.file_response import FileResponse -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getUploads( - self, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/uploads", - } - - return _kwargs - - -def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: - if response.status_code == 200: - response_200 = FileResponse.from_dict(response.json()) - - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getUploads(response=response), - ) - - -async def getUploads( - self, -) -> Optional[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - FileResponse - """ - - kwargs = self._get_kwargs_getUploads() - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getUploads(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py deleted file mode 100644 index ded1257..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employee.py +++ /dev/null @@ -1,80 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_employee_response_200 import GetEmployeeResponse200 -from ...models.not_found import NotFound -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getEmployee( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/users/{id}", - } - - return _kwargs - - -def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getEmployee(response=response), - ) - - -async def getEmployee( - self, - id: int, -) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetEmployeeResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getEmployee( - id=id, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getEmployee(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py deleted file mode 100644 index 1cefc69..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/employees/get_employees.py +++ /dev/null @@ -1,93 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_employees_response_200 import GetEmployeesResponse200 -from ...types import UNSET, Response, Unset -from .client_serv import HttpClient - - -def _get_kwargs_getEmployees( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, - query: Union[Unset, str] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["per"] = per - - params["page"] = page - - params["query"] = query - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/users", - "params": params, - } - - return _kwargs - - -def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: - if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) - - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getEmployees(response=response), - ) - - -async def getEmployees( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, - query: Union[Unset, str] = UNSET, -) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetEmployeesResponse200 - """ - - kwargs = self._get_kwargs_getEmployees( - per=per, - page=page, - query=query, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getEmployees(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py deleted file mode 100644 index 1b571d9..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/message/edit_message.py +++ /dev/null @@ -1,110 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.edit_message_body import EditMessageBody -from ...models.edit_message_response_200 import EditMessageResponse200 -from ...models.errors_code import ErrorsCode -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_editMessage( - self, - id: int, - body: EditMessageBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "put", - "url": f"/messages/{id}", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_editMessage( - self, response: httpx.Response -) -> Optional[Union[EditMessageResponse200, list["ErrorsCode"]]]: - if response.status_code == 200: - response_200 = EditMessageResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - - response_404.append(response_404_item) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_editMessage( - self, response: httpx.Response -) -> Response[Union[EditMessageResponse200, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_editMessage(response=response), - ) - - -async def editMessage( - self, - id: int, - body: EditMessageBody, -) -> Optional[Union[EditMessageResponse200, list["ErrorsCode"]]]: - """Редактирование сообщения - - Метод для редактирования сообщения или комментария. - - Args: - id (int): - body (EditMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[EditMessageResponse200, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_editMessage( - id=id, - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_editMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py deleted file mode 100644 index cbe2eee..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/create_message.py +++ /dev/null @@ -1,114 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.create_message_body import CreateMessageBody -from ...models.create_message_response_201 import CreateMessageResponse201 -from ...models.error import Error -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_createMessage( - self, - body: CreateMessageBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/messages", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_createMessage( - self, response: httpx.Response -) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - if response.status_code == 201: - response_201 = CreateMessageResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for componentsschemas_errors_item_data in _response_404: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - response_404.append(componentsschemas_errors_item) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createMessage( - self, response: httpx.Response -) -> Response[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createMessage(response=response), - ) - - -async def createMessage( - self, - body: CreateMessageBody, -) -> Optional[Union[BadRequest, CreateMessageResponse201, list["Error"]]]: - r"""создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \"discussion\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \"user\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - - Args: - body (CreateMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] - """ - - kwargs = self._get_kwargs_createMessage( - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_createMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py deleted file mode 100644 index bdd3107..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_list_message.py +++ /dev/null @@ -1,112 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_list_message_response_200 import GetListMessageResponse200 -from ...models.not_found import NotFound -from ...types import UNSET, Response, Unset -from .client_serv import HttpClient - - -def _get_kwargs_getListMessage( - self, - chat_id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["chat_id"] = chat_id - - params["per"] = per - - params["page"] = page - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/messages", - "params": params, - } - - return _kwargs - - -def _parse_response_getListMessage( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetListMessageResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getListMessage( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getListMessage(response=response), - ) - - -async def getListMessage( - self, - chat_id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - - Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetListMessageResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getListMessage( - chat_id=chat_id, - per=per, - page=page, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getListMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py deleted file mode 100644 index e5b336e..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/messages/get_message.py +++ /dev/null @@ -1,81 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_message_response_200 import GetMessageResponse200 -from ...models.not_found import NotFound -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getMessage( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/messages/{id}", - } - - return _kwargs - - -def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getMessage(response=response), - ) - - -async def getMessage( - self, - id: int, -) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetMessageResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getMessage( - id=id, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getMessage(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py deleted file mode 100644 index 43de16c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/delete_message_reactions.py +++ /dev/null @@ -1,98 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from ...models.delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from ...types import UNSET, Response -from .client_serv import HttpClient - - -def _get_kwargs_deleteMessageReactions( - self, - id: int, - code: str, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["code"] = code - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "delete", - "url": f"/messages/{id}/reactions", - "params": params, - } - - return _kwargs - - -def _parse_response_deleteMessageReactions( - self, response: httpx.Response -) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_deleteMessageReactions( - self, response: httpx.Response -) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_deleteMessageReactions(response=response), - ) - - -async def deleteMessageReactions( - self, - id: int, - code: str, -) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. - - Args: - id (int): - code (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] - """ - - kwargs = self._get_kwargs_deleteMessageReactions( - id=id, - code=code, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_deleteMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py deleted file mode 100644 index 1fef8f1..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/get_message_reactions.py +++ /dev/null @@ -1,102 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_message_reactions_body import GetMessageReactionsBody -from ...models.get_message_reactions_response_200 import GetMessageReactionsResponse200 -from ...models.not_found import NotFound -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getMessageReactions( - self, - id: int, - body: GetMessageReactionsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/messages/{id}/reactions", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_getMessageReactions( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getMessageReactions( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getMessageReactions(response=response), - ) - - -async def getMessageReactions( - self, - id: int, - body: GetMessageReactionsBody, -) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. - - Args: - id (int): - body (GetMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] - """ - - kwargs = self._get_kwargs_getMessageReactions( - id=id, - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py deleted file mode 100644 index d1f5daf..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reactions_to_messages/post_message_reactions.py +++ /dev/null @@ -1,112 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.post_message_reactions_body import PostMessageReactionsBody -from ...models.post_message_reactions_response_400 import PostMessageReactionsResponse400 -from ...models.post_message_reactions_response_403 import PostMessageReactionsResponse403 -from ...models.post_message_reactions_response_404 import PostMessageReactionsResponse404 -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_postMessageReactions( - self, - id: int, - body: PostMessageReactionsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/messages/{id}/reactions", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_postMessageReactions( - self, response: httpx.Response -) -> Optional[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) - - return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_postMessageReactions( - self, response: httpx.Response -) -> Response[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_postMessageReactions(response=response), - ) - - -async def postMessageReactions( - self, - id: int, - body: PostMessageReactionsBody, -) -> Optional[ - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] -]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (int): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] - """ - - kwargs = self._get_kwargs_postMessageReactions( - id=id, - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_postMessageReactions(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py deleted file mode 100644 index 693d2bf..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/reminders/create_task.py +++ /dev/null @@ -1,97 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.create_task_body import CreateTaskBody -from ...models.create_task_response_201 import CreateTaskResponse201 -from ...models.create_task_response_400 import CreateTaskResponse400 -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_createTask( - self, - body: CreateTaskBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": "/tasks", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_createTask( - self, response: httpx.Response -) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: - if response.status_code == 201: - response_201 = CreateTaskResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 400: - response_400 = CreateTaskResponse400.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_createTask( - self, response: httpx.Response -) -> Response[Union[CreateTaskResponse201, CreateTaskResponse400]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_createTask(response=response), - ) - - -async def createTask( - self, - body: CreateTaskBody, -) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (CreateTaskBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateTaskResponse201, CreateTaskResponse400] - """ - - kwargs = self._get_kwargs_createTask( - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_createTask(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py deleted file mode 100644 index 343eec6..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/del_status.py +++ /dev/null @@ -1,36 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...types import Response - - -def _get_kwargs_delStatus( - self, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "delete", - "url": "/profile/status", - } - - return _kwargs - - -def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_delStatus(response=response), - ) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py deleted file mode 100644 index c4612ea..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/get_status.py +++ /dev/null @@ -1,67 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional - -import httpx - -from ... import errors -from ...models.get_status_response_200 import GetStatusResponse200 -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getStatus( - self, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/profile/status", - } - - return _kwargs - - -def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: - if response.status_code == 200: - response_200 = GetStatusResponse200.from_dict(response.json()) - - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getStatus(response=response), - ) - - -async def getStatus( - self, -) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetStatusResponse200 - """ - - kwargs = self._get_kwargs_getStatus() - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getStatus(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py deleted file mode 100644 index 4b2dd51..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/status/put_status.py +++ /dev/null @@ -1,88 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.put_status_response_201 import PutStatusResponse201 -from ...models.query_status import QueryStatus -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_putStatus( - self, - body: QueryStatus, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "put", - "url": "/profile/status", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: - if response.status_code == 201: - response_201 = PutStatusResponse201.from_dict(response.json()) - - return response_201 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_putStatus(response=response), - ) - - -async def putStatus( - self, - body: QueryStatus, -) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус - - Создание нового статуса. - - Args: - body (QueryStatus): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, PutStatusResponse201] - """ - - kwargs = self._get_kwargs_putStatus( - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_putStatus(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py deleted file mode 100644 index 6e5992b..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tag.py +++ /dev/null @@ -1,79 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_tag_response_200 import GetTagResponse200 -from ...models.get_tag_response_404 import GetTagResponse404 -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_getTag( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/group_tags/{id}", - } - - return _kwargs - - -def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - if response.status_code == 200: - response_200 = GetTagResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = GetTagResponse404.from_dict(response.json()) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getTag(response=response), - ) - - -async def getTag( - self, - id: int, -) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге - - Параметры запроса отсутствуют - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagResponse200, GetTagResponse404] - """ - - kwargs = self._get_kwargs_getTag( - id=id, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getTag(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py deleted file mode 100644 index 88f1f16..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags.py +++ /dev/null @@ -1,92 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.get_tags_response_200 import GetTagsResponse200 -from ...models.get_tags_response_400 import GetTagsResponse400 -from ...types import UNSET, Response, Unset -from .client_serv import HttpClient - - -def _get_kwargs_getTags( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["per"] = per - - params["page"] = page - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/group_tags", - "params": params, - } - - return _kwargs - - -def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getTags(response=response), - ) - - -async def getTags( - self, - per: Union[Unset, int] = 50, - page: Union[Unset, int] = 1, -) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagsResponse200, GetTagsResponse400] - """ - - kwargs = self._get_kwargs_getTags( - per=per, - page=page, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getTags(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py deleted file mode 100644 index 7d80c24..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/tags/get_tags_employees.py +++ /dev/null @@ -1,100 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...models.bad_request import BadRequest -from ...models.get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from ...types import UNSET, Response, Unset -from .client_serv import HttpClient - - -def _get_kwargs_getTagsEmployees( - self, - id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["per"] = per - - params["page"] = page - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/group_tags/{id}/users", - "params": params, - } - - return _kwargs - - -def _parse_response_getTagsEmployees( - self, response: httpx.Response -) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_getTagsEmployees( - self, response: httpx.Response -) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_getTagsEmployees(response=response), - ) - - -async def getTagsEmployees( - self, - id: int, - per: Union[Unset, int] = 25, - page: Union[Unset, int] = 1, -) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetTagsEmployeesResponse200] - """ - - kwargs = self._get_kwargs_getTagsEmployees( - id=id, - per=per, - page=page, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_getTagsEmployees(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py deleted file mode 100644 index 1b751a4..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/leave_chat.py +++ /dev/null @@ -1,91 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_leaveChat( - self, - id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "delete", - "url": f"/chats/{id}/leave", - } - - return _kwargs - - -def _parse_response_leaveChat(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: - if response.status_code == 200: - response_200 = cast(Any, None) - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - - response_404.append(response_404_item) - - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_leaveChat(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_leaveChat(response=response), - ) - - -async def leaveChat( - self, - id: int, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """Выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_leaveChat( - id=id, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_leaveChat(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py deleted file mode 100644 index 3667224..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_members_to_chats.py +++ /dev/null @@ -1,95 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...models.post_members_to_chats_body import PostMembersToChatsBody -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_postMembersToChats( - self, - id: int, - body: PostMembersToChatsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/chats/{id}/members", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_postMembersToChats(response=response), - ) - - -async def postMembersToChats( - self, - id: int, - body: PostMembersToChatsBody, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostMembersToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_postMembersToChats( - id=id, - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_postMembersToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py deleted file mode 100644 index 11767db..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/api/talk_and_channel_participants/post_tags_to_chats.py +++ /dev/null @@ -1,95 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union, cast - -import httpx - -from ... import errors -from ...models.errors_code import ErrorsCode -from ...models.post_tags_to_chats_body import PostTagsToChatsBody -from ...types import Response -from .client_serv import HttpClient - - -def _get_kwargs_postTagsToChats( - self, - id: int, - body: PostTagsToChatsBody, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/chats/{id}/group_tags", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list["ErrorsCode"]]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - - response_400.append(response_400_item) - - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list["ErrorsCode"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=self._parse_response_postTagsToChats(response=response), - ) - - -async def postTagsToChats( - self, - id: int, - body: PostTagsToChatsBody, -) -> Optional[Union[Any, list["ErrorsCode"]]]: - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostTagsToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - - kwargs = self._get_kwargs_postTagsToChats( - id=id, - body=body, - ) - - # response = await self.client.get_async_httpx_client().request( - # **kwargs - # ) - response = await HttpClient.request( - method=kwargs["method"], url=kwargs["url"], **kwargs - ) # Используйте статичный метод - - return self._build_response_postTagsToChats(response=response).parsed diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py deleted file mode 100644 index d55c8ea..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client.py +++ /dev/null @@ -1,1517 +0,0 @@ -from .models import ( - BadRequest, - CreateChatBody, - CreateChatResponse201, - CreateChatResponse400, - CreateChatResponse404, - CreateChatResponse422, - CreateMessageBody, - CreateMessageResponse201, - CreateTaskBody, - CreateTaskResponse201, - CreateTaskResponse400, - CreateThreadResponse200, - DeleteMessageReactionsResponse400, - DeleteMessageReactionsResponse404, - DirectResponse, - EditMessageBody, - EditMessageResponse200, - Error, - ErrorsCode, - FileResponse, - GetChatResponse200, - GetChatResponse404, - GetChatsAvailability, - GetChatsResponse200, - GetChatsResponse400, - GetChatsResponse404, - GetChatsResponse422, - GetChatsSortid, - GetCommonMethodsResponse200, - GetEmployeeResponse200, - GetEmployeesResponse200, - GetListMessageResponse200, - GetMessageReactionsBody, - GetMessageReactionsResponse200, - GetMessageResponse200, - GetStatusResponse200, - GetTagResponse200, - GetTagResponse404, - GetTagsEmployeesResponse200, - GetTagsResponse200, - GetTagsResponse400, - NotFound, - PostMembersToChatsBody, - PostMessageReactionsBody, - PostMessageReactionsResponse400, - PostMessageReactionsResponse403, - PostMessageReactionsResponse404, - PostTagsToChatsBody, - PutStatusResponse201, - QueryStatus -) - -from typing import ( - Any, - Optional, - Union, - cast -) - -from .types import ( - Response, - UNSET, - Unset -) - -from . import errors -from .client_serv import HttpClient -from http import HTTPStatus - -import datetime - -import httpx -from .client_serv import HttpClient -import ssl -from typing import Any, Union, Optional - -from attrs import define, field, evolve - - -@define -class Client: - """A class for keeping track of data related to the API - - - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - - def with_headers(self, headers: dict[str, str]) -> "Client": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "Client": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "Client": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - - def set_httpx_client(self, client: httpx.Client) -> "Client": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "Client": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "Client": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - token: The token to use for authentication - prefix: The prefix to use for the Authorization header - auth_header_name: The name of the Authorization header - """ - - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -class Pachca: - """Главный класс библиотеки.""" - - def __init__(self, base_url, token): - self.client = AuthenticatedClient(base_url=base_url, token=token) - - - - def _get_kwargs_createChat(self, body: CreateChatBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/chats'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_createChat(self, response: httpx.Response) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - if response.status_code == 201: - response_201 = CreateChatResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = CreateChatResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = CreateChatResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = CreateChatResponse422.from_dict(response.json()) - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createChat(self, response: httpx.Response) -> Response[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createChat(response=response)) - - async def createChat(self, body: CreateChatBody) -> Optional[Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422]]: - """ Новая беседа или канал - - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\\ - - Args: - body (CreateChatBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateChatResponse201, CreateChatResponse400, CreateChatResponse404, CreateChatResponse422] - """ - kwargs = self._get_kwargs_createChat(body=body) - base_url = self.client._base_url # Получаем базовый URL из клиента - full_url = f"{base_url}{kwargs['url']}" # Формируем полный URL - kwargs['url'] = full_url # Обновляем URL в kwargs - response = await HttpClient.request(**kwargs) - # response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_createChat(response=response).parsed - - def _get_kwargs_getChat(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/chats/{id}'} - return _kwargs - - def _parse_response_getChat(self, response: httpx.Response) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - if response.status_code == 200: - response_200 = GetChatResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = GetChatResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getChat(self, response: httpx.Response) -> Response[Union[GetChatResponse200, GetChatResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChat(response=response)) - - async def getChat(self, id: int) -> Optional[Union[GetChatResponse200, GetChatResponse404]]: - """Информация о беседе или канале - - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatResponse200, GetChatResponse404] - """ - kwargs = self._get_kwargs_getChat(id=id) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getChat(response=response).parsed - - def _get_kwargs_getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - json_sortid: Union[Unset, str] = UNSET - if not isinstance(sortid, Unset): - json_sortid = sortid.value - params['sort[id]'] = json_sortid - params['per'] = per - params['page'] = page - json_availability: Union[Unset, str] = UNSET - if not isinstance(availability, Unset): - json_availability = availability.value - params['availability'] = json_availability - json_last_message_at_after: Union[Unset, str] = UNSET - if not isinstance(last_message_at_after, Unset): - json_last_message_at_after = last_message_at_after.isoformat() - params['last_message_at_after'] = json_last_message_at_after - json_last_message_at_before: Union[Unset, str] = UNSET - if not isinstance(last_message_at_before, Unset): - json_last_message_at_before = last_message_at_before.isoformat() - params['last_message_at_before'] = json_last_message_at_before - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/chats', 'params': params} - return _kwargs - - def _parse_response_getChats(self, response: httpx.Response) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - if response.status_code == 200: - response_200 = GetChatsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetChatsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = GetChatsResponse404.from_dict(response.json()) - return response_404 - if response.status_code == 422: - response_422 = GetChatsResponse422.from_dict(response.json()) - return response_422 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getChats(self, response: httpx.Response) -> Response[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getChats(response=response)) - - async def getChats(self, sortid: Union[Unset, GetChatsSortid]=GetChatsSortid.DESC, per: Union[Unset, int]=25, page: Union[Unset, int]=1, availability: Union[Unset, GetChatsAvailability]=GetChatsAvailability.IS_MEMBER, last_message_at_after: Union[Unset, datetime.datetime]=UNSET, last_message_at_before: Union[Unset, datetime.datetime]=UNSET) -> Optional[Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422]]: - """Список бесед и каналов - - Получения списка бесед и каналов по заданным параметрам. - - Args: - sortid (Union[Unset, GetChatsSortid]): Default: GetChatsSortid.DESC. - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - availability (Union[Unset, GetChatsAvailability]): Default: - GetChatsAvailability.IS_MEMBER. - last_message_at_after (Union[Unset, datetime.datetime]): - last_message_at_before (Union[Unset, datetime.datetime]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetChatsResponse200, GetChatsResponse400, GetChatsResponse404, GetChatsResponse422] - """ - kwargs = self._get_kwargs_getChats(sortid=sortid, per=per, page=page, availability=availability, last_message_at_after=last_message_at_after, last_message_at_before=last_message_at_before) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getChats(response=response).parsed - - def _get_kwargs_createThread(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/thread'} - return _kwargs - - def _parse_response_createThread(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - if response.status_code == 200: - response_200 = CreateThreadResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createThread(self, response: httpx.Response) -> Response[Union[BadRequest, CreateThreadResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createThread(response=response)) - - async def createThread(self, id: int) -> Optional[Union[BadRequest, CreateThreadResponse200, NotFound]]: - """Создание нового треда - - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в - ответе вернётся информация об уже созданном ранее треде. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateThreadResponse200, NotFound] - """ - kwargs = self._get_kwargs_createThread(id=id) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_createThread(response=response).parsed - - def _get_kwargs_getCommonMethods(self, entity_type: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['entity_type'] = entity_type - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/custom_properties', 'params': params} - return _kwargs - - def _parse_response_getCommonMethods(self, response: httpx.Response) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - if response.status_code == 200: - response_200 = GetCommonMethodsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getCommonMethods(self, response: httpx.Response) -> Response[Union[BadRequest, GetCommonMethodsResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getCommonMethods(response=response)) - - async def getCommonMethods(self, entity_type: str) -> Optional[Union[BadRequest, GetCommonMethodsResponse200]]: - """Список дополнительных полей - - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей - компании. - - Args: - entity_type (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetCommonMethodsResponse200] - """ - kwargs = self._get_kwargs_getCommonMethods(entity_type=entity_type) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getCommonMethods(response=response).parsed - - def _get_kwargs_getDirectUrl(self, body: DirectResponse) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/direct_url'} - _body = body.to_multipart() - _kwargs['files'] = _body - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_getDirectUrl(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getDirectUrl(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getDirectUrl(response=response)) - - def _get_kwargs_getUploads(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/uploads'} - return _kwargs - - def _parse_response_getUploads(self, response: httpx.Response) -> Optional[FileResponse]: - if response.status_code == 200: - response_200 = FileResponse.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getUploads(self, response: httpx.Response) -> Response[FileResponse]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getUploads(response=response)) - - async def getUploads(self) -> Optional[FileResponse]: - """Получение подписи и ключа для загрузки файла - - Возвращает параметры, необходимые для безопасной загрузки файла. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - FileResponse - """ - kwargs = self._get_kwargs_getUploads() - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getUploads(response=response).parsed - - def _get_kwargs_getEmployee(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/users/{id}'} - return _kwargs - - def _parse_response_getEmployee(self, response: httpx.Response) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetEmployeeResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getEmployee(self, response: httpx.Response) -> Response[Union[GetEmployeeResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployee(response=response)) - - async def getEmployee(self, id: int) -> Optional[Union[GetEmployeeResponse200, NotFound]]: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetEmployeeResponse200, NotFound] - """ - kwargs = self._get_kwargs_getEmployee(id=id) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getEmployee(response=response).parsed - - def _get_kwargs_getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params['query'] = query - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/users', 'params': params} - return _kwargs - - def _parse_response_getEmployees(self, response: httpx.Response) -> Optional[GetEmployeesResponse200]: - if response.status_code == 200: - response_200 = GetEmployeesResponse200.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getEmployees(self, response: httpx.Response) -> Response[GetEmployeesResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getEmployees(response=response)) - - async def getEmployees(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1, query: Union[Unset, str]=UNSET) -> Optional[GetEmployeesResponse200]: - """получение актуального списка всех сотрудников компании - - Fetch a paginated list of employees with optional filtering by query. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - query (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetEmployeesResponse200 - """ - kwargs = self._get_kwargs_getEmployees(per=per, page=page, query=query) - # Добавляем базовый URL к запросу - base_url = self.client._base_url # Получаем базовый URL из клиента - full_url = f"{base_url}{kwargs['url']}" # Формируем полный URL - kwargs['url'] = full_url # Обновляем URL в kwargs - import pdb;pdb.set_trace() - response = await HttpClient.request(**kwargs) - - # response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getEmployees(response=response).parsed - - def _get_kwargs_editMessage(self, id: int, body: EditMessageBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': f'/messages/{id}'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_editMessage(self, response: httpx.Response) -> Optional[Union[EditMessageResponse200, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = EditMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_editMessage(self, response: httpx.Response) -> Response[Union[EditMessageResponse200, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_editMessage(response=response)) - - async def editMessage(self, id: int, body: EditMessageBody) -> Optional[Union[EditMessageResponse200, list['ErrorsCode']]]: - """Редактирование сообщения - - Метод для редактирования сообщения или комментария. - - Args: - id (int): - body (EditMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[EditMessageResponse200, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_editMessage(id=id, body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_editMessage(response=response).parsed - - def _get_kwargs_createMessage(self, body: CreateMessageBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/messages'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_createMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - if response.status_code == 201: - response_201 = CreateMessageResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for componentsschemas_errors_item_data in _response_404: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - response_404.append(componentsschemas_errors_item) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createMessage(self, response: httpx.Response) -> Response[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createMessage(response=response)) - - async def createMessage(self, body: CreateMessageBody) -> Optional[Union[BadRequest, CreateMessageResponse201, list['Error']]]: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: \\"discussion\\" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: \\"user\\" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - - Args: - body (CreateMessageBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, CreateMessageResponse201, list['Error']] - """ - kwargs = self._get_kwargs_createMessage(body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_createMessage(response=response).parsed - - def _get_kwargs_getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['chat_id'] = chat_id - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/messages', 'params': params} - return _kwargs - - def _parse_response_getListMessage(self, response: httpx.Response) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetListMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getListMessage(self, response: httpx.Response) -> Response[Union[BadRequest, GetListMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getListMessage(response=response)) - - async def getListMessage(self, chat_id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetListMessageResponse200, NotFound]]: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - - Args: - chat_id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetListMessageResponse200, NotFound] - """ - kwargs = self._get_kwargs_getListMessage(chat_id=chat_id, per=per, page=page) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getListMessage(response=response).parsed - - def _get_kwargs_getMessage(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}'} - return _kwargs - - def _parse_response_getMessage(self, response: httpx.Response) -> Optional[Union[GetMessageResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getMessage(self, response: httpx.Response) -> Response[Union[GetMessageResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessage(response=response)) - - async def getMessage(self, id: int) -> Optional[Union[GetMessageResponse200, NotFound]]: - """получение информации о сообщении - - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetMessageResponse200, NotFound] - """ - kwargs = self._get_kwargs_getMessage(id=id) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getMessage(response=response).parsed - - def _get_kwargs_deleteMessageReactions(self, id: int, code: str) -> dict[str, Any]: - params: dict[str, Any] = {} - params['code'] = code - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/messages/{id}/reactions', 'params': params} - return _kwargs - - def _parse_response_deleteMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = DeleteMessageReactionsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 404: - response_404 = DeleteMessageReactionsResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_deleteMessageReactions(self, response: httpx.Response) -> Response[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_deleteMessageReactions(response=response)) - - async def deleteMessageReactions(self, id: int, code: str) -> Optional[Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404]]: - """Удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены - авторизованным пользователем. - - Args: - id (int): - code (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, DeleteMessageReactionsResponse400, DeleteMessageReactionsResponse404] - """ - kwargs = self._get_kwargs_deleteMessageReactions(id=id, code=code) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_deleteMessageReactions(response=response).parsed - - def _get_kwargs_getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_getMessageReactions(self, response: httpx.Response) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - if response.status_code == 200: - response_200 = GetMessageReactionsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = NotFound.from_dict(response.json()) - return response_404 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getMessageReactions(self, response: httpx.Response) -> Response[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getMessageReactions(response=response)) - - async def getMessageReactions(self, id: int, body: GetMessageReactionsBody) -> Optional[Union[BadRequest, GetMessageReactionsResponse200, NotFound]]: - """Получение актуального списка реакций. - - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное - сообщение. - - Args: - id (int): - body (GetMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetMessageReactionsResponse200, NotFound] - """ - kwargs = self._get_kwargs_getMessageReactions(id=id, body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getMessageReactions(response=response).parsed - - def _get_kwargs_postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/messages/{id}/reactions'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postMessageReactions(self, response: httpx.Response) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - if response.status_code == 204: - response_204 = cast(Any, None) - return response_204 - if response.status_code == 400: - response_400 = PostMessageReactionsResponse400.from_dict(response.json()) - return response_400 - if response.status_code == 403: - response_403 = PostMessageReactionsResponse403.from_dict(response.json()) - return response_403 - if response.status_code == 404: - response_404 = PostMessageReactionsResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postMessageReactions(self, response: httpx.Response) -> Response[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMessageReactions(response=response)) - - async def postMessageReactions(self, id: int, body: PostMessageReactionsBody) -> Optional[Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404]]: - """Добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый пользователь может - установить не более 20 уникальных реакций на сообщение. - Сообщение может иметь не более 30 - уникальных реакций. - Сообщение может иметь не более 1000 реакций. - - Args: - id (int): - body (PostMessageReactionsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, PostMessageReactionsResponse400, PostMessageReactionsResponse403, PostMessageReactionsResponse404] - """ - kwargs = self._get_kwargs_postMessageReactions(id=id, body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_postMessageReactions(response=response).parsed - - def _get_kwargs_createTask(self, body: CreateTaskBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': '/tasks'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_createTask(self, response: httpx.Response) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: - if response.status_code == 201: - response_201 = CreateTaskResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = CreateTaskResponse400.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_createTask(self, response: httpx.Response) -> Response[Union[CreateTaskResponse201, CreateTaskResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_createTask(response=response)) - - async def createTask(self, body: CreateTaskBody) -> Optional[Union[CreateTaskResponse201, CreateTaskResponse400]]: - """Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, - простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим - текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - - Args: - body (CreateTaskBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateTaskResponse201, CreateTaskResponse400] - """ - kwargs = self._get_kwargs_createTask(body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_createTask(response=response).parsed - - def _get_kwargs_delStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': '/profile/status'} - return _kwargs - - def _parse_response_delStatus(self, response: httpx.Response) -> Optional[Any]: - if response.status_code == 204: - return None - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_delStatus(self, response: httpx.Response) -> Response[Any]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_delStatus(response=response)) - - def _get_kwargs_getStatus(self) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/profile/status'} - return _kwargs - - def _parse_response_getStatus(self, response: httpx.Response) -> Optional[GetStatusResponse200]: - if response.status_code == 200: - response_200 = GetStatusResponse200.from_dict(response.json()) - return response_200 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getStatus(self, response: httpx.Response) -> Response[GetStatusResponse200]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getStatus(response=response)) - - async def getStatus(self) -> Optional[GetStatusResponse200]: - """получение информации о своем статусе - - Параметры запроса отсутствуют - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - GetStatusResponse200 - """ - kwargs = self._get_kwargs_getStatus() - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getStatus(response=response).parsed - - def _get_kwargs_putStatus(self, body: QueryStatus) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'put', 'url': '/profile/status'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_putStatus(self, response: httpx.Response) -> Optional[Union[BadRequest, PutStatusResponse201]]: - if response.status_code == 201: - response_201 = PutStatusResponse201.from_dict(response.json()) - return response_201 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_putStatus(self, response: httpx.Response) -> Response[Union[BadRequest, PutStatusResponse201]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_putStatus(response=response)) - - async def putStatus(self, body: QueryStatus) -> Optional[Union[BadRequest, PutStatusResponse201]]: - """новый статус - - Создание нового статуса. - - Args: - body (QueryStatus): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, PutStatusResponse201] - """ - kwargs = self._get_kwargs_putStatus(body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_putStatus(response=response).parsed - - def _get_kwargs_getTag(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}'} - return _kwargs - - def _parse_response_getTag(self, response: httpx.Response) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - if response.status_code == 200: - response_200 = GetTagResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 404: - response_404 = GetTagResponse404.from_dict(response.json()) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTag(self, response: httpx.Response) -> Response[Union[GetTagResponse200, GetTagResponse404]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTag(response=response)) - - async def getTag(self, id: int) -> Optional[Union[GetTagResponse200, GetTagResponse404]]: - """Информация о теге - - Параметры запроса отсутствуют - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagResponse200, GetTagResponse404] - """ - kwargs = self._get_kwargs_getTag(id=id) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getTag(response=response).parsed - - def _get_kwargs_getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': '/group_tags', 'params': params} - return _kwargs - - def _parse_response_getTags(self, response: httpx.Response) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - if response.status_code == 200: - response_200 = GetTagsResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = GetTagsResponse400.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTags(self, response: httpx.Response) -> Response[Union[GetTagsResponse200, GetTagsResponse400]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTags(response=response)) - - async def getTags(self, per: Union[Unset, int]=50, page: Union[Unset, int]=1) -> Optional[Union[GetTagsResponse200, GetTagsResponse400]]: - """Список тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. - - Args: - per (Union[Unset, int]): Default: 50. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[GetTagsResponse200, GetTagsResponse400] - """ - kwargs = self._get_kwargs_getTags(per=per, page=page) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getTags(response=response).parsed - - def _get_kwargs_getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> dict[str, Any]: - params: dict[str, Any] = {} - params['per'] = per - params['page'] = page - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: dict[str, Any] = {'method': 'get', 'url': f'/group_tags/{id}/users', 'params': params} - return _kwargs - - def _parse_response_getTagsEmployees(self, response: httpx.Response) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - if response.status_code == 200: - response_200 = GetTagsEmployeesResponse200.from_dict(response.json()) - return response_200 - if response.status_code == 400: - response_400 = BadRequest.from_dict(response.json()) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_getTagsEmployees(self, response: httpx.Response) -> Response[Union[BadRequest, GetTagsEmployeesResponse200]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_getTagsEmployees(response=response)) - - async def getTagsEmployees(self, id: int, per: Union[Unset, int]=25, page: Union[Unset, int]=1) -> Optional[Union[BadRequest, GetTagsEmployeesResponse200]]: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. - - Args: - id (int): - per (Union[Unset, int]): Default: 25. - page (Union[Unset, int]): Default: 1. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[BadRequest, GetTagsEmployeesResponse200] - """ - kwargs = self._get_kwargs_getTagsEmployees(id=id, per=per, page=page) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_getTagsEmployees(response=response).parsed - - def _get_kwargs_leaveChat(self, id: int) -> dict[str, Any]: - _kwargs: dict[str, Any] = {'method': 'delete', 'url': f'/chats/{id}/leave'} - return _kwargs - - def _parse_response_leaveChat(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 200: - response_200 = cast(Any, None) - return response_200 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if response.status_code == 404: - response_404 = [] - _response_404 = response.json() - for response_404_item_data in _response_404: - response_404_item = ErrorsCode.from_dict(response_404_item_data) - response_404.append(response_404_item) - return response_404 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_leaveChat(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_leaveChat(response=response)) - - async def leaveChat(self, id: int) -> Optional[Union[Any, list['ErrorsCode']]]: - """Выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. - - Args: - id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_leaveChat(id=id) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_leaveChat(response=response).parsed - - def _get_kwargs_postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/members'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postMembersToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postMembersToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postMembersToChats(response=response)) - - async def postMembersToChats(self, id: int, body: PostMembersToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostMembersToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_postMembersToChats(id=id, body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_postMembersToChats(response=response).parsed - - def _get_kwargs_postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> dict[str, Any]: - headers: dict[str, Any] = {} - _kwargs: dict[str, Any] = {'method': 'post', 'url': f'/chats/{id}/group_tags'} - _body = body.to_dict() - _kwargs['json'] = _body - headers['Content-Type'] = 'application/json' - _kwargs['headers'] = headers - return _kwargs - - def _parse_response_postTagsToChats(self, response: httpx.Response) -> Optional[Union[Any, list['ErrorsCode']]]: - if response.status_code == 201: - response_201 = cast(Any, None) - return response_201 - if response.status_code == 400: - response_400 = [] - _response_400 = response.json() - for response_400_item_data in _response_400: - response_400_item = ErrorsCode.from_dict(response_400_item_data) - response_400.append(response_400_item) - return response_400 - if self.client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - def _build_response_postTagsToChats(self, response: httpx.Response) -> Response[Union[Any, list['ErrorsCode']]]: - return Response(status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, parsed=self._parse_response_postTagsToChats(response=response)) - - async def postTagsToChats(self, id: int, body: PostTagsToChatsBody) -> Optional[Union[Any, list['ErrorsCode']]]: - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - - Args: - id (int): Example: 533. - body (PostTagsToChatsBody): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, list['ErrorsCode']] - """ - kwargs = self._get_kwargs_postTagsToChats(id=id, body=body) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) - return self._build_response_postTagsToChats(response=response).parsed - - - \ No newline at end of file diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py deleted file mode 100644 index f1a9b65..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/client_serv.py +++ /dev/null @@ -1,9 +0,0 @@ -import httpx -from typing import Any, Dict - -class HttpClient: - @staticmethod - async def request(method: str, url: str, **kwargs: Any) -> httpx.Response: - async with httpx.AsyncClient() as client: - response = await client.request(method, url, **kwargs) - return response diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py deleted file mode 100644 index 5f92e76..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/errors.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Contains shared errors types that can be raised from API functions""" - - -class UnexpectedStatus(Exception): - """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" - - def __init__(self, status_code: int, content: bytes): - self.status_code = status_code - self.content = content - - super().__init__( - f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" - ) - - -__all__ = ["UnexpectedStatus"] diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py deleted file mode 100644 index 6138024..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/__init__.py +++ /dev/null @@ -1,189 +0,0 @@ -"""Contains all the data models used in inputs/outputs""" - -from .bad_request import BadRequest -from .base_employee import BaseEmployee -from .base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem -from .button import Button -from .chat import Chat -from .create_chat_body import CreateChatBody -from .create_chat_response_201 import CreateChatResponse201 -from .create_chat_response_400 import CreateChatResponse400 -from .create_chat_response_404 import CreateChatResponse404 -from .create_chat_response_422 import CreateChatResponse422 -from .create_message import CreateMessage -from .create_message_body import CreateMessageBody -from .create_message_entity_type import CreateMessageEntityType -from .create_message_files_item import CreateMessageFilesItem -from .create_message_files_item_file_type import CreateMessageFilesItemFileType -from .create_message_response_201 import CreateMessageResponse201 -from .create_task_body import CreateTaskBody -from .create_task_body_task import CreateTaskBodyTask -from .create_task_body_task_custom_properties_item import CreateTaskBodyTaskCustomPropertiesItem -from .create_task_response_201 import CreateTaskResponse201 -from .create_task_response_201_data import CreateTaskResponse201Data -from .create_task_response_201_data_custom_properties_item import CreateTaskResponse201DataCustomPropertiesItem -from .create_task_response_400 import CreateTaskResponse400 -from .create_thread_response_200 import CreateThreadResponse200 -from .create_thread_response_200_data import CreateThreadResponse200Data -from .delete_message_reactions_response_400 import DeleteMessageReactionsResponse400 -from .delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem -from .delete_message_reactions_response_400_errors_item_payload import ( - DeleteMessageReactionsResponse400ErrorsItemPayload, -) -from .delete_message_reactions_response_404 import DeleteMessageReactionsResponse404 -from .delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem -from .delete_message_reactions_response_404_errors_item_payload import ( - DeleteMessageReactionsResponse404ErrorsItemPayload, -) -from .direct_response import DirectResponse -from .edit_message_body import EditMessageBody -from .edit_message_response_200 import EditMessageResponse200 -from .edit_messages import EditMessages -from .edit_messages_buttons_item_item import EditMessagesButtonsItemItem -from .edit_messages_files import EditMessagesFiles -from .edit_messages_files_file_type import EditMessagesFilesFileType -from .employee import Employee -from .error import Error -from .error_payload import ErrorPayload -from .errors_code import ErrorsCode -from .errors_code_payload import ErrorsCodePayload -from .file_response import FileResponse -from .get_chat_response_200 import GetChatResponse200 -from .get_chat_response_404 import GetChatResponse404 -from .get_chats_availability import GetChatsAvailability -from .get_chats_response_200 import GetChatsResponse200 -from .get_chats_response_400 import GetChatsResponse400 -from .get_chats_response_404 import GetChatsResponse404 -from .get_chats_response_422 import GetChatsResponse422 -from .get_chats_sortid import GetChatsSortid -from .get_common_methods_response_200 import GetCommonMethodsResponse200 -from .get_employee_response_200 import GetEmployeeResponse200 -from .get_employees_response_200 import GetEmployeesResponse200 -from .get_list_message_response_200 import GetListMessageResponse200 -from .get_message_reactions_body import GetMessageReactionsBody -from .get_message_reactions_response_200 import GetMessageReactionsResponse200 -from .get_message_response_200 import GetMessageResponse200 -from .get_status_response_200 import GetStatusResponse200 -from .get_tag_response_200 import GetTagResponse200 -from .get_tag_response_404 import GetTagResponse404 -from .get_tag_response_404_errors_item import GetTagResponse404ErrorsItem -from .get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload -from .get_tags_employees_response_200 import GetTagsEmployeesResponse200 -from .get_tags_response_200 import GetTagsResponse200 -from .get_tags_response_400 import GetTagsResponse400 -from .get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem -from .get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload -from .message import Message -from .message_entity_type import MessageEntityType -from .message_files_item import MessageFilesItem -from .message_files_item_file_type import MessageFilesItemFileType -from .message_forwarding import MessageForwarding -from .message_thread import MessageThread -from .not_found import NotFound -from .post_members_to_chats_body import PostMembersToChatsBody -from .post_message_reactions_body import PostMessageReactionsBody -from .post_message_reactions_response_400 import PostMessageReactionsResponse400 -from .post_message_reactions_response_403 import PostMessageReactionsResponse403 -from .post_message_reactions_response_404 import PostMessageReactionsResponse404 -from .post_tags_to_chats_body import PostTagsToChatsBody -from .put_status_response_201 import PutStatusResponse201 -from .query_chat import QueryChat -from .query_common_methods import QueryCommonMethods -from .query_status import QueryStatus -from .query_status_status import QueryStatusStatus -from .reaction import Reaction -from .status_type_0 import StatusType0 -from .tag import Tag - -__all__ = ( - "BadRequest", - "BaseEmployee", - "BaseEmployeeCustomPropertiesItem", - "Button", - "Chat", - "CreateChatBody", - "CreateChatResponse201", - "CreateChatResponse400", - "CreateChatResponse404", - "CreateChatResponse422", - "CreateMessage", - "CreateMessageBody", - "CreateMessageEntityType", - "CreateMessageFilesItem", - "CreateMessageFilesItemFileType", - "CreateMessageResponse201", - "CreateTaskBody", - "CreateTaskBodyTask", - "CreateTaskBodyTaskCustomPropertiesItem", - "CreateTaskResponse201", - "CreateTaskResponse201Data", - "CreateTaskResponse201DataCustomPropertiesItem", - "CreateTaskResponse400", - "CreateThreadResponse200", - "CreateThreadResponse200Data", - "DeleteMessageReactionsResponse400", - "DeleteMessageReactionsResponse400ErrorsItem", - "DeleteMessageReactionsResponse400ErrorsItemPayload", - "DeleteMessageReactionsResponse404", - "DeleteMessageReactionsResponse404ErrorsItem", - "DeleteMessageReactionsResponse404ErrorsItemPayload", - "DirectResponse", - "EditMessageBody", - "EditMessageResponse200", - "EditMessages", - "EditMessagesButtonsItemItem", - "EditMessagesFiles", - "EditMessagesFilesFileType", - "Employee", - "Error", - "ErrorPayload", - "ErrorsCode", - "ErrorsCodePayload", - "FileResponse", - "GetChatResponse200", - "GetChatResponse404", - "GetChatsAvailability", - "GetChatsResponse200", - "GetChatsResponse400", - "GetChatsResponse404", - "GetChatsResponse422", - "GetChatsSortid", - "GetCommonMethodsResponse200", - "GetEmployeeResponse200", - "GetEmployeesResponse200", - "GetListMessageResponse200", - "GetMessageReactionsBody", - "GetMessageReactionsResponse200", - "GetMessageResponse200", - "GetStatusResponse200", - "GetTagResponse200", - "GetTagResponse404", - "GetTagResponse404ErrorsItem", - "GetTagResponse404ErrorsItemPayload", - "GetTagsEmployeesResponse200", - "GetTagsResponse200", - "GetTagsResponse400", - "GetTagsResponse400ErrorsItem", - "GetTagsResponse400ErrorsItemPayload", - "Message", - "MessageEntityType", - "MessageFilesItem", - "MessageFilesItemFileType", - "MessageForwarding", - "MessageThread", - "NotFound", - "PostMembersToChatsBody", - "PostMessageReactionsBody", - "PostMessageReactionsResponse400", - "PostMessageReactionsResponse403", - "PostMessageReactionsResponse404", - "PostTagsToChatsBody", - "PutStatusResponse201", - "QueryChat", - "QueryCommonMethods", - "QueryStatus", - "QueryStatusStatus", - "Reaction", - "StatusType0", - "Tag", -) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py deleted file mode 100644 index 17dd6ed..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/bad_request.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="BadRequest") - - -@_attrs_define -class BadRequest: - """ - Attributes: - error (Union[Unset, str]): - message (Union[Unset, str]): - """ - - error: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - message = self.message - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - if message is not UNSET: - field_dict["message"] = message - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - message = d.pop("message", UNSET) - - bad_request = cls( - error=error, - message=message, - ) - - bad_request.additional_properties = d - return bad_request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py deleted file mode 100644 index b6a0314..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee.py +++ /dev/null @@ -1,186 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - - -T = TypeVar("T", bound="BaseEmployee") - - -@_attrs_define -class BaseEmployee: - """Базовый класс сотрудника. - - Attributes: - id (Union[Unset, int]): Идентификатор пользователя Example: 1. - first_name (Union[Unset, str]): Имя - last_name (Union[Unset, str]): Фамилия - nickname (Union[Unset, str]): Имя пользователя - email (Union[Unset, str]): Электронная почта - phone_number (Union[Unset, str]): Телефон - department (Union[Unset, str]): Департамент - role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является - деактивированным. - invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) - list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику - custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника - bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) - """ - - id: Union[Unset, int] = UNSET - first_name: Union[Unset, str] = UNSET - last_name: Union[Unset, str] = UNSET - nickname: Union[Unset, str] = UNSET - email: Union[Unset, str] = UNSET - phone_number: Union[Unset, str] = UNSET - department: Union[Unset, str] = UNSET - role: Union[Unset, str] = UNSET - suspended: Union[Unset, bool] = UNSET - invite_status: Union[Unset, str] = UNSET - list_tags: Union[Unset, list[str]] = UNSET - custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET - bot: Union[Unset, bool] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - first_name = self.first_name - - last_name = self.last_name - - nickname = self.nickname - - email = self.email - - phone_number = self.phone_number - - department = self.department - - role = self.role - - suspended = self.suspended - - invite_status = self.invite_status - - list_tags: Union[Unset, list[str]] = UNSET - if not isinstance(self.list_tags, Unset): - list_tags = self.list_tags - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - bot = self.bot - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if first_name is not UNSET: - field_dict["first_name"] = first_name - if last_name is not UNSET: - field_dict["last_name"] = last_name - if nickname is not UNSET: - field_dict["nickname"] = nickname - if email is not UNSET: - field_dict["email"] = email - if phone_number is not UNSET: - field_dict["phone_number"] = phone_number - if department is not UNSET: - field_dict["department"] = department - if role is not UNSET: - field_dict["role"] = role - if suspended is not UNSET: - field_dict["suspended"] = suspended - if invite_status is not UNSET: - field_dict["invite_status"] = invite_status - if list_tags is not UNSET: - field_dict["list_tags"] = list_tags - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - if bot is not UNSET: - field_dict["bot"] = bot - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - - d = src_dict.copy() - id = d.pop("id", UNSET) - - first_name = d.pop("first_name", UNSET) - - last_name = d.pop("last_name", UNSET) - - nickname = d.pop("nickname", UNSET) - - email = d.pop("email", UNSET) - - phone_number = d.pop("phone_number", UNSET) - - department = d.pop("department", UNSET) - - role = d.pop("role", UNSET) - - suspended = d.pop("suspended", UNSET) - - invite_status = d.pop("invite_status", UNSET) - - list_tags = cast(list[str], d.pop("list_tags", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - bot = d.pop("bot", UNSET) - - base_employee = cls( - id=id, - first_name=first_name, - last_name=last_name, - nickname=nickname, - email=email, - phone_number=phone_number, - department=department, - role=role, - suspended=suspended, - invite_status=invite_status, - list_tags=list_tags, - custom_properties=custom_properties, - bot=bot, - ) - - base_employee.additional_properties = d - return base_employee - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py deleted file mode 100644 index bee25c8..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/base_employee_custom_properties_item.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="BaseEmployeeCustomPropertiesItem") - - -@_attrs_define -class BaseEmployeeCustomPropertiesItem: - """ - Attributes: - id (Union[Unset, int]): Идентификатор поля - name (Union[Unset, str]): Название поля - data_type (Union[Unset, str]): Тип поля (string, number, date или link) - value (Union[Unset, str]): Значение - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - data_type: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - data_type = self.data_type - - value = self.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if data_type is not UNSET: - field_dict["data_type"] = data_type - if value is not UNSET: - field_dict["value"] = value - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - data_type = d.pop("data_type", UNSET) - - value = d.pop("value", UNSET) - - base_employee_custom_properties_item = cls( - id=id, - name=name, - data_type=data_type, - value=value, - ) - - base_employee_custom_properties_item.additional_properties = d - return base_employee_custom_properties_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py deleted file mode 100644 index 64ea323..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/button.py +++ /dev/null @@ -1,78 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Button") - - -@_attrs_define -class Button: - """ - Attributes: - text (str): - url (Union[Unset, str]): - data (Union[Unset, str]): - """ - - text: str - url: Union[Unset, str] = UNSET - data: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - text = self.text - - url = self.url - - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "text": text, - } - ) - if url is not UNSET: - field_dict["url"] = url - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - text = d.pop("text") - - url = d.pop("url", UNSET) - - data = d.pop("data", UNSET) - - button = cls( - text=text, - url=url, - data=data, - ) - - button.additional_properties = d - return button - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py deleted file mode 100644 index 7ef2560..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/chat.py +++ /dev/null @@ -1,162 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Chat") - - -@_attrs_define -class Chat: - """Беседа или канал - - Attributes: - id (Union[Unset, int]): Идентификатор беседы или канала Example: 334. - name (Union[Unset, str]): Название Example: 🤿 aqua. - owner_id (Union[Unset, int]): Идентификатор пользователя, создавшего беседу или канал Example: 185. - created_at (Union[Unset, datetime.datetime]): Дата и время создания беседы или канала (ISO-8601, UTC+0) в - формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:56:53.000Z. - member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, участников Example: [185, 186, 187]. - group_tag_ids (Union[Unset, list[int]]): Массив идентификаторов тегов, участников - channel (Union[Unset, bool]): Тип: беседа (false) или канал (true) Example: True. - public (Union[Unset, bool]): Доступ: закрытый (false) или открытый (true) - last_message_at (Union[Unset, datetime.datetime]): Дата и время создания последнего сообщения в беседе/канале - (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ Example: 2021-08-28T15:58:13.000Z. - meet_room_url (Union[Unset, str]): Ссылка на Видеочат Example: https://meet.pachca.com/aqua-94bb21b5. - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - owner_id: Union[Unset, int] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - member_ids: Union[Unset, list[int]] = UNSET - group_tag_ids: Union[Unset, list[int]] = UNSET - channel: Union[Unset, bool] = UNSET - public: Union[Unset, bool] = UNSET - last_message_at: Union[Unset, datetime.datetime] = UNSET - meet_room_url: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - owner_id = self.owner_id - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - member_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.member_ids, Unset): - member_ids = self.member_ids - - group_tag_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.group_tag_ids, Unset): - group_tag_ids = self.group_tag_ids - - channel = self.channel - - public = self.public - - last_message_at: Union[Unset, str] = UNSET - if not isinstance(self.last_message_at, Unset): - last_message_at = self.last_message_at.isoformat() - - meet_room_url = self.meet_room_url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if owner_id is not UNSET: - field_dict["owner_id"] = owner_id - if created_at is not UNSET: - field_dict["created_at"] = created_at - if member_ids is not UNSET: - field_dict["member_ids"] = member_ids - if group_tag_ids is not UNSET: - field_dict["group_tag_ids"] = group_tag_ids - if channel is not UNSET: - field_dict["channel"] = channel - if public is not UNSET: - field_dict["public"] = public - if last_message_at is not UNSET: - field_dict["last_message_at"] = last_message_at - if meet_room_url is not UNSET: - field_dict["meet_room_url"] = meet_room_url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - owner_id = d.pop("owner_id", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - member_ids = cast(list[int], d.pop("member_ids", UNSET)) - - group_tag_ids = cast(list[int], d.pop("group_tag_ids", UNSET)) - - channel = d.pop("channel", UNSET) - - public = d.pop("public", UNSET) - - _last_message_at = d.pop("last_message_at", UNSET) - last_message_at: Union[Unset, datetime.datetime] - if isinstance(_last_message_at, Unset): - last_message_at = UNSET - else: - last_message_at = isoparse(_last_message_at) - - meet_room_url = d.pop("meet_room_url", UNSET) - - chat = cls( - id=id, - name=name, - owner_id=owner_id, - created_at=created_at, - member_ids=member_ids, - group_tag_ids=group_tag_ids, - channel=channel, - public=public, - last_message_at=last_message_at, - meet_room_url=meet_room_url, - ) - - chat.additional_properties = d - return chat - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py deleted file mode 100644 index 8b9e361..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_body.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.query_chat import QueryChat - - -T = TypeVar("T", bound="CreateChatBody") - - -@_attrs_define -class CreateChatBody: - """ - Attributes: - chat (Union[Unset, QueryChat]): Собранный объект параметров создаваемой беседы или канала - """ - - chat: Union[Unset, "QueryChat"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - chat: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.chat, Unset): - chat = self.chat.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if chat is not UNSET: - field_dict["chat"] = chat - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.query_chat import QueryChat - - d = src_dict.copy() - _chat = d.pop("chat", UNSET) - chat: Union[Unset, QueryChat] - if isinstance(_chat, Unset): - chat = UNSET - else: - chat = QueryChat.from_dict(_chat) - - create_chat_body = cls( - chat=chat, - ) - - create_chat_body.additional_properties = d - return create_chat_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py deleted file mode 100644 index 3a928ef..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_201.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.chat import Chat - - -T = TypeVar("T", bound="CreateChatResponse201") - - -@_attrs_define -class CreateChatResponse201: - """ - Attributes: - data (Union[Unset, Chat]): Беседа или канал - """ - - data: Union[Unset, "Chat"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.chat import Chat - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Chat] - if isinstance(_data, Unset): - data = UNSET - else: - data = Chat.from_dict(_data) - - create_chat_response_201 = cls( - data=data, - ) - - create_chat_response_201.additional_properties = d - return create_chat_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py deleted file mode 100644 index 1d7fd30..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_400.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="CreateChatResponse400") - - -@_attrs_define -class CreateChatResponse400: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - create_chat_response_400 = cls( - errors=errors, - ) - - create_chat_response_400.additional_properties = d - return create_chat_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py deleted file mode 100644 index 3de2654..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="CreateChatResponse404") - - -@_attrs_define -class CreateChatResponse404: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - create_chat_response_404 = cls( - errors=errors, - ) - - create_chat_response_404.additional_properties = d - return create_chat_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py deleted file mode 100644 index c917758..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_chat_response_422.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="CreateChatResponse422") - - -@_attrs_define -class CreateChatResponse422: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - create_chat_response_422 = cls( - errors=errors, - ) - - create_chat_response_422.additional_properties = d - return create_chat_response_422 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py deleted file mode 100644 index 63e52de..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message.py +++ /dev/null @@ -1,178 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.create_message_entity_type import CreateMessageEntityType -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.button import Button - from ..models.create_message_files_item import CreateMessageFilesItem - - -T = TypeVar("T", bound="CreateMessage") - - -@_attrs_define -class CreateMessage: - """ - Attributes: - entity_id (int): - content (str): - entity_type (Union[Unset, CreateMessageEntityType]): Default: CreateMessageEntityType.DISCUSSION. - files (Union[Unset, list['CreateMessageFilesItem']]): - buttons (Union[Unset, list[list['Button']]]): - parent_message_id (Union[None, Unset, int]): - skip_invite_mentions (Union[Unset, bool]): Default: False. - link_preview (Union[Unset, bool]): Default: False. - """ - - entity_id: int - content: str - entity_type: Union[Unset, CreateMessageEntityType] = CreateMessageEntityType.DISCUSSION - files: Union[Unset, list["CreateMessageFilesItem"]] = UNSET - buttons: Union[Unset, list[list["Button"]]] = UNSET - parent_message_id: Union[None, Unset, int] = UNSET - skip_invite_mentions: Union[Unset, bool] = False - link_preview: Union[Unset, bool] = False - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - entity_id = self.entity_id - - content = self.content - - entity_type: Union[Unset, str] = UNSET - if not isinstance(self.entity_type, Unset): - entity_type = self.entity_type.value - - files: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.files, Unset): - files = [] - for files_item_data in self.files: - files_item = files_item_data.to_dict() - files.append(files_item) - - buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET - if not isinstance(self.buttons, Unset): - buttons = [] - for componentsschemas_buttons_item_data in self.buttons: - componentsschemas_buttons_item = [] - for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: - componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - parent_message_id: Union[None, Unset, int] - if isinstance(self.parent_message_id, Unset): - parent_message_id = UNSET - else: - parent_message_id = self.parent_message_id - - skip_invite_mentions = self.skip_invite_mentions - - link_preview = self.link_preview - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "entity_id": entity_id, - "content": content, - } - ) - if entity_type is not UNSET: - field_dict["entity_type"] = entity_type - if files is not UNSET: - field_dict["files"] = files - if buttons is not UNSET: - field_dict["buttons"] = buttons - if parent_message_id is not UNSET: - field_dict["parent_message_id"] = parent_message_id - if skip_invite_mentions is not UNSET: - field_dict["skip_invite_mentions"] = skip_invite_mentions - if link_preview is not UNSET: - field_dict["link_preview"] = link_preview - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.button import Button - from ..models.create_message_files_item import CreateMessageFilesItem - - d = src_dict.copy() - entity_id = d.pop("entity_id") - - content = d.pop("content") - - _entity_type = d.pop("entity_type", UNSET) - entity_type: Union[Unset, CreateMessageEntityType] - if isinstance(_entity_type, Unset): - entity_type = UNSET - else: - entity_type = CreateMessageEntityType(_entity_type) - - files = [] - _files = d.pop("files", UNSET) - for files_item_data in _files or []: - files_item = CreateMessageFilesItem.from_dict(files_item_data) - - files.append(files_item) - - buttons = [] - _buttons = d.pop("buttons", UNSET) - for componentsschemas_buttons_item_data in _buttons or []: - componentsschemas_buttons_item = [] - _componentsschemas_buttons_item = componentsschemas_buttons_item_data - for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: - componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) - - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) - - skip_invite_mentions = d.pop("skip_invite_mentions", UNSET) - - link_preview = d.pop("link_preview", UNSET) - - create_message = cls( - entity_id=entity_id, - content=content, - entity_type=entity_type, - files=files, - buttons=buttons, - parent_message_id=parent_message_id, - skip_invite_mentions=skip_invite_mentions, - link_preview=link_preview, - ) - - create_message.additional_properties = d - return create_message - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py deleted file mode 100644 index a8960fe..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_body.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_message import CreateMessage - - -T = TypeVar("T", bound="CreateMessageBody") - - -@_attrs_define -class CreateMessageBody: - """ - Attributes: - message (Union[Unset, CreateMessage]): - """ - - message: Union[Unset, "CreateMessage"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - message: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.message, Unset): - message = self.message.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if message is not UNSET: - field_dict["message"] = message - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_message import CreateMessage - - d = src_dict.copy() - _message = d.pop("message", UNSET) - message: Union[Unset, CreateMessage] - if isinstance(_message, Unset): - message = UNSET - else: - message = CreateMessage.from_dict(_message) - - create_message_body = cls( - message=message, - ) - - create_message_body.additional_properties = d - return create_message_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py deleted file mode 100644 index 067c6f4..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_entity_type.py +++ /dev/null @@ -1,10 +0,0 @@ -from enum import Enum - - -class CreateMessageEntityType(str, Enum): - DISCUSSION = "discussion" - THREAD = "thread" - USER = "user" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py deleted file mode 100644 index a7c8ee3..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item.py +++ /dev/null @@ -1,84 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.create_message_files_item_file_type import CreateMessageFilesItemFileType - -T = TypeVar("T", bound="CreateMessageFilesItem") - - -@_attrs_define -class CreateMessageFilesItem: - """ - Attributes: - key (str): - name (str): - file_type (CreateMessageFilesItemFileType): - size (int): - """ - - key: str - name: str - file_type: CreateMessageFilesItemFileType - size: int - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - name = self.name - - file_type = self.file_type.value - - size = self.size - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "key": key, - "name": name, - "file_type": file_type, - "size": size, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - key = d.pop("key") - - name = d.pop("name") - - file_type = CreateMessageFilesItemFileType(d.pop("file_type")) - - size = d.pop("size") - - create_message_files_item = cls( - key=key, - name=name, - file_type=file_type, - size=size, - ) - - create_message_files_item.additional_properties = d - return create_message_files_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py deleted file mode 100644 index 89889f9..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_files_item_file_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class CreateMessageFilesItemFileType(str, Enum): - FILE = "file" - IMAGE = "image" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py deleted file mode 100644 index b016d4c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_message_response_201.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="CreateMessageResponse201") - - -@_attrs_define -class CreateMessageResponse201: - """ - Attributes: - data (Union[Unset, Message]): - """ - - data: Union[Unset, "Message"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Message] - if isinstance(_data, Unset): - data = UNSET - else: - data = Message.from_dict(_data) - - create_message_response_201 = cls( - data=data, - ) - - create_message_response_201.additional_properties = d - return create_message_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py deleted file mode 100644 index c99dbf2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_task_body_task import CreateTaskBodyTask - - -T = TypeVar("T", bound="CreateTaskBody") - - -@_attrs_define -class CreateTaskBody: - """ - Attributes: - task (Union[Unset, CreateTaskBodyTask]): - """ - - task: Union[Unset, "CreateTaskBodyTask"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - task: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.task, Unset): - task = self.task.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if task is not UNSET: - field_dict["task"] = task - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_task_body_task import CreateTaskBodyTask - - d = src_dict.copy() - _task = d.pop("task", UNSET) - task: Union[Unset, CreateTaskBodyTask] - if isinstance(_task, Unset): - task = UNSET - else: - task = CreateTaskBodyTask.from_dict(_task) - - create_task_body = cls( - task=task, - ) - - create_task_body.additional_properties = d - return create_task_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py deleted file mode 100644 index f441ba6..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task.py +++ /dev/null @@ -1,123 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_task_body_task_custom_properties_item import CreateTaskBodyTaskCustomPropertiesItem - - -T = TypeVar("T", bound="CreateTaskBodyTask") - - -@_attrs_define -class CreateTaskBodyTask: - """ - Attributes: - kind (str): Тип напоминания (call, meeting, reminder, event, email) - content (str): Описание напоминания - due_at (datetime.datetime): Срок выполнения напоминания (ISO-8601) - priority (Union[Unset, int]): Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей - custom_properties (Union[Unset, list['CreateTaskBodyTaskCustomPropertiesItem']]): - """ - - kind: str - content: str - due_at: datetime.datetime - priority: Union[Unset, int] = UNSET - performer_ids: Union[Unset, list[int]] = UNSET - custom_properties: Union[Unset, list["CreateTaskBodyTaskCustomPropertiesItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - kind = self.kind - - content = self.content - - due_at = self.due_at.isoformat() - - priority = self.priority - - performer_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.performer_ids, Unset): - performer_ids = self.performer_ids - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "kind": kind, - "content": content, - "due_at": due_at, - } - ) - if priority is not UNSET: - field_dict["priority"] = priority - if performer_ids is not UNSET: - field_dict["performer_ids"] = performer_ids - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_task_body_task_custom_properties_item import CreateTaskBodyTaskCustomPropertiesItem - - d = src_dict.copy() - kind = d.pop("kind") - - content = d.pop("content") - - due_at = isoparse(d.pop("due_at")) - - priority = d.pop("priority", UNSET) - - performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = CreateTaskBodyTaskCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - create_task_body_task = cls( - kind=kind, - content=content, - due_at=due_at, - priority=priority, - performer_ids=performer_ids, - custom_properties=custom_properties, - ) - - create_task_body_task.additional_properties = d - return create_task_body_task - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py deleted file mode 100644 index 7e4a42d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_body_task_custom_properties_item.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateTaskBodyTaskCustomPropertiesItem") - - -@_attrs_define -class CreateTaskBodyTaskCustomPropertiesItem: - """ - Attributes: - id (Union[Unset, int]): Идентификатор поля - value (Union[Unset, str]): Значение поля - """ - - id: Union[Unset, int] = UNSET - value: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - value = self.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if value is not UNSET: - field_dict["value"] = value - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - value = d.pop("value", UNSET) - - create_task_body_task_custom_properties_item = cls( - id=id, - value=value, - ) - - create_task_body_task_custom_properties_item.additional_properties = d - return create_task_body_task_custom_properties_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py deleted file mode 100644 index f34110e..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_task_response_201_data import CreateTaskResponse201Data - - -T = TypeVar("T", bound="CreateTaskResponse201") - - -@_attrs_define -class CreateTaskResponse201: - """ - Attributes: - data (Union[Unset, CreateTaskResponse201Data]): - """ - - data: Union[Unset, "CreateTaskResponse201Data"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_task_response_201_data import CreateTaskResponse201Data - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, CreateTaskResponse201Data] - if isinstance(_data, Unset): - data = UNSET - else: - data = CreateTaskResponse201Data.from_dict(_data) - - create_task_response_201 = cls( - data=data, - ) - - create_task_response_201.additional_properties = d - return create_task_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py deleted file mode 100644 index f9179d1..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data.py +++ /dev/null @@ -1,179 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_task_response_201_data_custom_properties_item import ( - CreateTaskResponse201DataCustomPropertiesItem, - ) - - -T = TypeVar("T", bound="CreateTaskResponse201Data") - - -@_attrs_define -class CreateTaskResponse201Data: - """ - Attributes: - id (Union[Unset, int]): Идентификатор созданного напоминания - kind (Union[Unset, str]): Тип - content (Union[Unset, str]): Описание - due_at (Union[Unset, datetime.datetime]): Срок выполнения (ISO-8601) - priority (Union[Unset, int]): Приоритет - user_id (Union[Unset, int]): Идентификатор пользователя-создателя - status (Union[Unset, str]): Статус напоминания - created_at (Union[Unset, datetime.datetime]): Дата и время создания - performer_ids (Union[Unset, list[int]]): - custom_properties (Union[Unset, list['CreateTaskResponse201DataCustomPropertiesItem']]): - """ - - id: Union[Unset, int] = UNSET - kind: Union[Unset, str] = UNSET - content: Union[Unset, str] = UNSET - due_at: Union[Unset, datetime.datetime] = UNSET - priority: Union[Unset, int] = UNSET - user_id: Union[Unset, int] = UNSET - status: Union[Unset, str] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - performer_ids: Union[Unset, list[int]] = UNSET - custom_properties: Union[Unset, list["CreateTaskResponse201DataCustomPropertiesItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - kind = self.kind - - content = self.content - - due_at: Union[Unset, str] = UNSET - if not isinstance(self.due_at, Unset): - due_at = self.due_at.isoformat() - - priority = self.priority - - user_id = self.user_id - - status = self.status - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - performer_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.performer_ids, Unset): - performer_ids = self.performer_ids - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if kind is not UNSET: - field_dict["kind"] = kind - if content is not UNSET: - field_dict["content"] = content - if due_at is not UNSET: - field_dict["due_at"] = due_at - if priority is not UNSET: - field_dict["priority"] = priority - if user_id is not UNSET: - field_dict["user_id"] = user_id - if status is not UNSET: - field_dict["status"] = status - if created_at is not UNSET: - field_dict["created_at"] = created_at - if performer_ids is not UNSET: - field_dict["performer_ids"] = performer_ids - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_task_response_201_data_custom_properties_item import ( - CreateTaskResponse201DataCustomPropertiesItem, - ) - - d = src_dict.copy() - id = d.pop("id", UNSET) - - kind = d.pop("kind", UNSET) - - content = d.pop("content", UNSET) - - _due_at = d.pop("due_at", UNSET) - due_at: Union[Unset, datetime.datetime] - if isinstance(_due_at, Unset): - due_at = UNSET - else: - due_at = isoparse(_due_at) - - priority = d.pop("priority", UNSET) - - user_id = d.pop("user_id", UNSET) - - status = d.pop("status", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - performer_ids = cast(list[int], d.pop("performer_ids", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = CreateTaskResponse201DataCustomPropertiesItem.from_dict( - custom_properties_item_data - ) - - custom_properties.append(custom_properties_item) - - create_task_response_201_data = cls( - id=id, - kind=kind, - content=content, - due_at=due_at, - priority=priority, - user_id=user_id, - status=status, - created_at=created_at, - performer_ids=performer_ids, - custom_properties=custom_properties, - ) - - create_task_response_201_data.additional_properties = d - return create_task_response_201_data - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py deleted file mode 100644 index 05e003e..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_201_data_custom_properties_item.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateTaskResponse201DataCustomPropertiesItem") - - -@_attrs_define -class CreateTaskResponse201DataCustomPropertiesItem: - """ - Attributes: - id (Union[Unset, int]): Идентификатор поля - name (Union[Unset, str]): Название поля - data_type (Union[Unset, str]): Тип поля (string, number, date или link) - value (Union[Unset, str]): Значение - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - data_type: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - data_type = self.data_type - - value = self.value - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if data_type is not UNSET: - field_dict["data_type"] = data_type - if value is not UNSET: - field_dict["value"] = value - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - data_type = d.pop("data_type", UNSET) - - value = d.pop("value", UNSET) - - create_task_response_201_data_custom_properties_item = cls( - id=id, - name=name, - data_type=data_type, - value=value, - ) - - create_task_response_201_data_custom_properties_item.additional_properties = d - return create_task_response_201_data_custom_properties_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py deleted file mode 100644 index ae66b97..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_task_response_400.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateTaskResponse400") - - -@_attrs_define -class CreateTaskResponse400: - """ - Attributes: - error (Union[Unset, str]): Описание ошибки - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - create_task_response_400 = cls( - error=error, - ) - - create_task_response_400.additional_properties = d - return create_task_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py deleted file mode 100644 index 15fd0b4..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.create_thread_response_200_data import CreateThreadResponse200Data - - -T = TypeVar("T", bound="CreateThreadResponse200") - - -@_attrs_define -class CreateThreadResponse200: - """ - Attributes: - data (Union[Unset, CreateThreadResponse200Data]): - """ - - data: Union[Unset, "CreateThreadResponse200Data"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.create_thread_response_200_data import CreateThreadResponse200Data - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, CreateThreadResponse200Data] - if isinstance(_data, Unset): - data = UNSET - else: - data = CreateThreadResponse200Data.from_dict(_data) - - create_thread_response_200 = cls( - data=data, - ) - - create_thread_response_200.additional_properties = d - return create_thread_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py deleted file mode 100644 index 93b7457..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/create_thread_response_200_data.py +++ /dev/null @@ -1,104 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateThreadResponse200Data") - - -@_attrs_define -class CreateThreadResponse200Data: - """ - Attributes: - id (Union[Unset, int]): Идентификатор созданного треда. - chat_id (Union[Unset, int]): Идентификатор чата треда. - message_id (Union[Unset, int]): Идентификатор сообщения, к которому был создан тред. - message_chat_id (Union[Unset, int]): Идентификатор чата сообщения. - updated_at (Union[Unset, datetime.datetime]): Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM- - DDThh:mm:ss.sssZ. - """ - - id: Union[Unset, int] = UNSET - chat_id: Union[Unset, int] = UNSET - message_id: Union[Unset, int] = UNSET - message_chat_id: Union[Unset, int] = UNSET - updated_at: Union[Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - chat_id = self.chat_id - - message_id = self.message_id - - message_chat_id = self.message_chat_id - - updated_at: Union[Unset, str] = UNSET - if not isinstance(self.updated_at, Unset): - updated_at = self.updated_at.isoformat() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if chat_id is not UNSET: - field_dict["chat_id"] = chat_id - if message_id is not UNSET: - field_dict["message_id"] = message_id - if message_chat_id is not UNSET: - field_dict["message_chat_id"] = message_chat_id - if updated_at is not UNSET: - field_dict["updated_at"] = updated_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - chat_id = d.pop("chat_id", UNSET) - - message_id = d.pop("message_id", UNSET) - - message_chat_id = d.pop("message_chat_id", UNSET) - - _updated_at = d.pop("updated_at", UNSET) - updated_at: Union[Unset, datetime.datetime] - if isinstance(_updated_at, Unset): - updated_at = UNSET - else: - updated_at = isoparse(_updated_at) - - create_thread_response_200_data = cls( - id=id, - chat_id=chat_id, - message_id=message_id, - message_chat_id=message_chat_id, - updated_at=updated_at, - ) - - create_thread_response_200_data.additional_properties = d - return create_thread_response_200_data - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py deleted file mode 100644 index 100dc9c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_400_errors_item import DeleteMessageReactionsResponse400ErrorsItem - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse400") - - -@_attrs_define -class DeleteMessageReactionsResponse400: - """ - Attributes: - errors (Union[Unset, list['DeleteMessageReactionsResponse400ErrorsItem']]): Список ошибок в запросе. - """ - - errors: Union[Unset, list["DeleteMessageReactionsResponse400ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_400_errors_item import ( - DeleteMessageReactionsResponse400ErrorsItem, - ) - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = DeleteMessageReactionsResponse400ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - delete_message_reactions_response_400 = cls( - errors=errors, - ) - - delete_message_reactions_response_400.additional_properties = d - return delete_message_reactions_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py deleted file mode 100644 index 4a61277..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item.py +++ /dev/null @@ -1,111 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_400_errors_item_payload import ( - DeleteMessageReactionsResponse400ErrorsItemPayload, - ) - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItem") - - -@_attrs_define -class DeleteMessageReactionsResponse400ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. - value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. - message (Union[Unset, str]): Текстовое описание ошибки. - code (Union[Unset, str]): Внутренний код ошибки. - payload (Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "DeleteMessageReactionsResponse400ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_400_errors_item_payload import ( - DeleteMessageReactionsResponse400ErrorsItemPayload, - ) - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, DeleteMessageReactionsResponse400ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = DeleteMessageReactionsResponse400ErrorsItemPayload.from_dict(_payload) - - delete_message_reactions_response_400_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - delete_message_reactions_response_400_errors_item.additional_properties = d - return delete_message_reactions_response_400_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py deleted file mode 100644 index d3d26c9..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_400_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="DeleteMessageReactionsResponse400ErrorsItemPayload") - - -@_attrs_define -class DeleteMessageReactionsResponse400ErrorsItemPayload: - """Дополнительная информация об ошибке.""" - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - delete_message_reactions_response_400_errors_item_payload = cls() - - delete_message_reactions_response_400_errors_item_payload.additional_properties = d - return delete_message_reactions_response_400_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py deleted file mode 100644 index 9f918a0..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_404_errors_item import DeleteMessageReactionsResponse404ErrorsItem - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse404") - - -@_attrs_define -class DeleteMessageReactionsResponse404: - """ - Attributes: - errors (Union[Unset, list['DeleteMessageReactionsResponse404ErrorsItem']]): Список ошибок. - """ - - errors: Union[Unset, list["DeleteMessageReactionsResponse404ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_404_errors_item import ( - DeleteMessageReactionsResponse404ErrorsItem, - ) - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = DeleteMessageReactionsResponse404ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - delete_message_reactions_response_404 = cls( - errors=errors, - ) - - delete_message_reactions_response_404.additional_properties = d - return delete_message_reactions_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py deleted file mode 100644 index 849db9d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item.py +++ /dev/null @@ -1,111 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.delete_message_reactions_response_404_errors_item_payload import ( - DeleteMessageReactionsResponse404ErrorsItemPayload, - ) - - -T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItem") - - -@_attrs_define -class DeleteMessageReactionsResponse404ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "DeleteMessageReactionsResponse404ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.delete_message_reactions_response_404_errors_item_payload import ( - DeleteMessageReactionsResponse404ErrorsItemPayload, - ) - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, DeleteMessageReactionsResponse404ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = DeleteMessageReactionsResponse404ErrorsItemPayload.from_dict(_payload) - - delete_message_reactions_response_404_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - delete_message_reactions_response_404_errors_item.additional_properties = d - return delete_message_reactions_response_404_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py deleted file mode 100644 index f2fa5b5..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/delete_message_reactions_response_404_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="DeleteMessageReactionsResponse404ErrorsItemPayload") - - -@_attrs_define -class DeleteMessageReactionsResponse404ErrorsItemPayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - delete_message_reactions_response_404_errors_item_payload = cls() - - delete_message_reactions_response_404_errors_item_payload.additional_properties = d - return delete_message_reactions_response_404_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py deleted file mode 100644 index aef4bc1..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/direct_response.py +++ /dev/null @@ -1,195 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DirectResponse") - - -@_attrs_define -class DirectResponse: - """ - Attributes: - content_disposition (Union[Unset, str]): - acl (Union[Unset, str]): - policy (Union[Unset, str]): - x_amz_credential (Union[Unset, str]): - x_amz_algorithm (Union[Unset, str]): - x_amz_date (Union[Unset, str]): - x_amz_signature (Union[Unset, str]): - key (Union[Unset, str]): - file (Union[Unset, str]): - """ - - content_disposition: Union[Unset, str] = UNSET - acl: Union[Unset, str] = UNSET - policy: Union[Unset, str] = UNSET - x_amz_credential: Union[Unset, str] = UNSET - x_amz_algorithm: Union[Unset, str] = UNSET - x_amz_date: Union[Unset, str] = UNSET - x_amz_signature: Union[Unset, str] = UNSET - key: Union[Unset, str] = UNSET - file: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - content_disposition = self.content_disposition - - acl = self.acl - - policy = self.policy - - x_amz_credential = self.x_amz_credential - - x_amz_algorithm = self.x_amz_algorithm - - x_amz_date = self.x_amz_date - - x_amz_signature = self.x_amz_signature - - key = self.key - - file = self.file - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if content_disposition is not UNSET: - field_dict["Content-Disposition"] = content_disposition - if acl is not UNSET: - field_dict["acl"] = acl - if policy is not UNSET: - field_dict["policy"] = policy - if x_amz_credential is not UNSET: - field_dict["x-amz-credential"] = x_amz_credential - if x_amz_algorithm is not UNSET: - field_dict["x-amz-algorithm"] = x_amz_algorithm - if x_amz_date is not UNSET: - field_dict["x-amz-date"] = x_amz_date - if x_amz_signature is not UNSET: - field_dict["x-amz-signature"] = x_amz_signature - if key is not UNSET: - field_dict["key"] = key - if file is not UNSET: - field_dict["file"] = file - - return field_dict - - def to_multipart(self) -> dict[str, Any]: - content_disposition = ( - self.content_disposition - if isinstance(self.content_disposition, Unset) - else (None, str(self.content_disposition).encode(), "text/plain") - ) - - acl = self.acl if isinstance(self.acl, Unset) else (None, str(self.acl).encode(), "text/plain") - - policy = self.policy if isinstance(self.policy, Unset) else (None, str(self.policy).encode(), "text/plain") - - x_amz_credential = ( - self.x_amz_credential - if isinstance(self.x_amz_credential, Unset) - else (None, str(self.x_amz_credential).encode(), "text/plain") - ) - - x_amz_algorithm = ( - self.x_amz_algorithm - if isinstance(self.x_amz_algorithm, Unset) - else (None, str(self.x_amz_algorithm).encode(), "text/plain") - ) - - x_amz_date = ( - self.x_amz_date - if isinstance(self.x_amz_date, Unset) - else (None, str(self.x_amz_date).encode(), "text/plain") - ) - - x_amz_signature = ( - self.x_amz_signature - if isinstance(self.x_amz_signature, Unset) - else (None, str(self.x_amz_signature).encode(), "text/plain") - ) - - key = self.key if isinstance(self.key, Unset) else (None, str(self.key).encode(), "text/plain") - - file = self.file if isinstance(self.file, Unset) else (None, str(self.file).encode(), "text/plain") - - field_dict: dict[str, Any] = {} - for prop_name, prop in self.additional_properties.items(): - field_dict[prop_name] = (None, str(prop).encode(), "text/plain") - - field_dict.update({}) - if content_disposition is not UNSET: - field_dict["Content-Disposition"] = content_disposition - if acl is not UNSET: - field_dict["acl"] = acl - if policy is not UNSET: - field_dict["policy"] = policy - if x_amz_credential is not UNSET: - field_dict["x-amz-credential"] = x_amz_credential - if x_amz_algorithm is not UNSET: - field_dict["x-amz-algorithm"] = x_amz_algorithm - if x_amz_date is not UNSET: - field_dict["x-amz-date"] = x_amz_date - if x_amz_signature is not UNSET: - field_dict["x-amz-signature"] = x_amz_signature - if key is not UNSET: - field_dict["key"] = key - if file is not UNSET: - field_dict["file"] = file - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - content_disposition = d.pop("Content-Disposition", UNSET) - - acl = d.pop("acl", UNSET) - - policy = d.pop("policy", UNSET) - - x_amz_credential = d.pop("x-amz-credential", UNSET) - - x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) - - x_amz_date = d.pop("x-amz-date", UNSET) - - x_amz_signature = d.pop("x-amz-signature", UNSET) - - key = d.pop("key", UNSET) - - file = d.pop("file", UNSET) - - direct_response = cls( - content_disposition=content_disposition, - acl=acl, - policy=policy, - x_amz_credential=x_amz_credential, - x_amz_algorithm=x_amz_algorithm, - x_amz_date=x_amz_date, - x_amz_signature=x_amz_signature, - key=key, - file=file, - ) - - direct_response.additional_properties = d - return direct_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py deleted file mode 100644 index cb91797..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_body.py +++ /dev/null @@ -1,72 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.edit_messages import EditMessages - - -T = TypeVar("T", bound="EditMessageBody") - - -@_attrs_define -class EditMessageBody: - """ - Attributes: - message (Union[Unset, EditMessages]): Для получения сообщения вам необходимо знать его id и указать его в URL - запроса. - """ - - message: Union[Unset, "EditMessages"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - message: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.message, Unset): - message = self.message.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if message is not UNSET: - field_dict["message"] = message - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.edit_messages import EditMessages - - d = src_dict.copy() - _message = d.pop("message", UNSET) - message: Union[Unset, EditMessages] - if isinstance(_message, Unset): - message = UNSET - else: - message = EditMessages.from_dict(_message) - - edit_message_body = cls( - message=message, - ) - - edit_message_body.additional_properties = d - return edit_message_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py deleted file mode 100644 index 8893ed2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_message_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="EditMessageResponse200") - - -@_attrs_define -class EditMessageResponse200: - """ - Attributes: - data (Union[Unset, list['Message']]): Созданное сообщение - """ - - data: Union[Unset, list["Message"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Message.from_dict(data_item_data) - - data.append(data_item) - - edit_message_response_200 = cls( - data=data, - ) - - edit_message_response_200.additional_properties = d - return edit_message_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py deleted file mode 100644 index 8e6439d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages.py +++ /dev/null @@ -1,113 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem - from ..models.edit_messages_files import EditMessagesFiles - - -T = TypeVar("T", bound="EditMessages") - - -@_attrs_define -class EditMessages: - """Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - - Attributes: - content (Union[Unset, str]): Текст сообщения Default: 'Текст сообщения'. - files (Union[Unset, EditMessagesFiles]): - buttons (Union[Unset, list[list['EditMessagesButtonsItemItem']]]): Массив строк, каждая из которых представлена - массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в - статье. Для удаления кнопок у сообщения пришлите пустой массив. - """ - - content: Union[Unset, str] = "Текст сообщения" - files: Union[Unset, "EditMessagesFiles"] = UNSET - buttons: Union[Unset, list[list["EditMessagesButtonsItemItem"]]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - content = self.content - - files: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.files, Unset): - files = self.files.to_dict() - - buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET - if not isinstance(self.buttons, Unset): - buttons = [] - for buttons_item_data in self.buttons: - buttons_item = [] - for buttons_item_item_data in buttons_item_data: - buttons_item_item = buttons_item_item_data.to_dict() - buttons_item.append(buttons_item_item) - - buttons.append(buttons_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if content is not UNSET: - field_dict["content"] = content - if files is not UNSET: - field_dict["files"] = files - if buttons is not UNSET: - field_dict["buttons"] = buttons - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.edit_messages_buttons_item_item import EditMessagesButtonsItemItem - from ..models.edit_messages_files import EditMessagesFiles - - d = src_dict.copy() - content = d.pop("content", UNSET) - - _files = d.pop("files", UNSET) - files: Union[Unset, EditMessagesFiles] - if isinstance(_files, Unset): - files = UNSET - else: - files = EditMessagesFiles.from_dict(_files) - - buttons = [] - _buttons = d.pop("buttons", UNSET) - for buttons_item_data in _buttons or []: - buttons_item = [] - _buttons_item = buttons_item_data - for buttons_item_item_data in _buttons_item: - buttons_item_item = EditMessagesButtonsItemItem.from_dict(buttons_item_item_data) - - buttons_item.append(buttons_item_item) - - buttons.append(buttons_item) - - edit_messages = cls( - content=content, - files=files, - buttons=buttons, - ) - - edit_messages.additional_properties = d - return edit_messages - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py deleted file mode 100644 index 22494f8..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_buttons_item_item.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="EditMessagesButtonsItemItem") - - -@_attrs_define -class EditMessagesButtonsItemItem: - """ - Attributes: - text (Union[Unset, str]): Текст, отображаемый на кнопке пользователю - url (Union[Unset, str]): Ссылка, которая будет открыта по нажатию кнопки - data (Union[Unset, str]): Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки - """ - - text: Union[Unset, str] = UNSET - url: Union[Unset, str] = UNSET - data: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - text = self.text - - url = self.url - - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if text is not UNSET: - field_dict["text"] = text - if url is not UNSET: - field_dict["url"] = url - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - text = d.pop("text", UNSET) - - url = d.pop("url", UNSET) - - data = d.pop("data", UNSET) - - edit_messages_buttons_item_item = cls( - text=text, - url=url, - data=data, - ) - - edit_messages_buttons_item_item.additional_properties = d - return edit_messages_buttons_item_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py deleted file mode 100644 index f42b7bb..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files.py +++ /dev/null @@ -1,95 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.edit_messages_files_file_type import EditMessagesFilesFileType -from ..types import UNSET, Unset - -T = TypeVar("T", bound="EditMessagesFiles") - - -@_attrs_define -class EditMessagesFiles: - """ - Attributes: - key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении - должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе - с расширением) - file_type (Union[Unset, EditMessagesFilesFileType]): - size (Union[Unset, int]): Размер файла в байтах, отображаемый пользователю Default: 1234. - """ - - key: Union[Unset, str] = UNSET - name: Union[Unset, str] = UNSET - file_type: Union[Unset, EditMessagesFilesFileType] = UNSET - size: Union[Unset, int] = 1234 - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - name = self.name - - file_type: Union[Unset, str] = UNSET - if not isinstance(self.file_type, Unset): - file_type = self.file_type.value - - size = self.size - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if name is not UNSET: - field_dict["name"] = name - if file_type is not UNSET: - field_dict["file_type"] = file_type - if size is not UNSET: - field_dict["size"] = size - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - key = d.pop("key", UNSET) - - name = d.pop("name", UNSET) - - _file_type = d.pop("file_type", UNSET) - file_type: Union[Unset, EditMessagesFilesFileType] - if isinstance(_file_type, Unset): - file_type = UNSET - else: - file_type = EditMessagesFilesFileType(_file_type) - - size = d.pop("size", UNSET) - - edit_messages_files = cls( - key=key, - name=name, - file_type=file_type, - size=size, - ) - - edit_messages_files.additional_properties = d - return edit_messages_files - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py deleted file mode 100644 index a78a223..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/edit_messages_files_file_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class EditMessagesFilesFileType(str, Enum): - FILE = "file" - IMAGE = "image" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py deleted file mode 100644 index 9011165..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/employee.py +++ /dev/null @@ -1,275 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - from ..models.status_type_0 import StatusType0 - - -T = TypeVar("T", bound="Employee") - - -@_attrs_define -class Employee: - """ - Attributes: - id (Union[Unset, int]): Идентификатор пользователя Example: 1. - first_name (Union[Unset, str]): Имя - last_name (Union[Unset, str]): Фамилия - nickname (Union[Unset, str]): Имя пользователя - email (Union[Unset, str]): Электронная почта - phone_number (Union[Unset, str]): Телефон - department (Union[Unset, str]): Департамент - role (Union[Unset, str]): Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended (Union[Unset, bool]): Деактивация пользователя. При значении true пользователь является - деактивированным. - invite_status (Union[Unset, str]): Статус приглашения: confirmed (принято), sent (отправлено) - list_tags (Union[Unset, list[str]]): Массив тегов, привязанных к сотруднику - custom_properties (Union[Unset, list['BaseEmployeeCustomPropertiesItem']]): Дополнительные поля сотрудника - bot (Union[Unset, bool]): Тип: пользователь (false) или бот (true) - user_status (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. - title (Union[Unset, str]): Должность - created_at (Union[Unset, datetime.datetime]): Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone (Union[Unset, str]): Часовой пояс пользователя - image_url (Union[None, Unset, str]): Ссылка на скачивание аватарки - """ - - id: Union[Unset, int] = UNSET - first_name: Union[Unset, str] = UNSET - last_name: Union[Unset, str] = UNSET - nickname: Union[Unset, str] = UNSET - email: Union[Unset, str] = UNSET - phone_number: Union[Unset, str] = UNSET - department: Union[Unset, str] = UNSET - role: Union[Unset, str] = UNSET - suspended: Union[Unset, bool] = UNSET - invite_status: Union[Unset, str] = UNSET - list_tags: Union[Unset, list[str]] = UNSET - custom_properties: Union[Unset, list["BaseEmployeeCustomPropertiesItem"]] = UNSET - bot: Union[Unset, bool] = UNSET - user_status: Union["StatusType0", None, Unset] = UNSET - title: Union[Unset, str] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - time_zone: Union[Unset, str] = UNSET - image_url: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.status_type_0 import StatusType0 - - id = self.id - - first_name = self.first_name - - last_name = self.last_name - - nickname = self.nickname - - email = self.email - - phone_number = self.phone_number - - department = self.department - - role = self.role - - suspended = self.suspended - - invite_status = self.invite_status - - list_tags: Union[Unset, list[str]] = UNSET - if not isinstance(self.list_tags, Unset): - list_tags = self.list_tags - - custom_properties: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.custom_properties, Unset): - custom_properties = [] - for custom_properties_item_data in self.custom_properties: - custom_properties_item = custom_properties_item_data.to_dict() - custom_properties.append(custom_properties_item) - - bot = self.bot - - user_status: Union[None, Unset, dict[str, Any]] - if isinstance(self.user_status, Unset): - user_status = UNSET - elif isinstance(self.user_status, StatusType0): - user_status = self.user_status.to_dict() - else: - user_status = self.user_status - - title = self.title - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - time_zone = self.time_zone - - image_url: Union[None, Unset, str] - if isinstance(self.image_url, Unset): - image_url = UNSET - else: - image_url = self.image_url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if first_name is not UNSET: - field_dict["first_name"] = first_name - if last_name is not UNSET: - field_dict["last_name"] = last_name - if nickname is not UNSET: - field_dict["nickname"] = nickname - if email is not UNSET: - field_dict["email"] = email - if phone_number is not UNSET: - field_dict["phone_number"] = phone_number - if department is not UNSET: - field_dict["department"] = department - if role is not UNSET: - field_dict["role"] = role - if suspended is not UNSET: - field_dict["suspended"] = suspended - if invite_status is not UNSET: - field_dict["invite_status"] = invite_status - if list_tags is not UNSET: - field_dict["list_tags"] = list_tags - if custom_properties is not UNSET: - field_dict["custom_properties"] = custom_properties - if bot is not UNSET: - field_dict["bot"] = bot - if user_status is not UNSET: - field_dict["user_status"] = user_status - if title is not UNSET: - field_dict["title"] = title - if created_at is not UNSET: - field_dict["created_at"] = created_at - if time_zone is not UNSET: - field_dict["time_zone"] = time_zone - if image_url is not UNSET: - field_dict["image_url"] = image_url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.base_employee_custom_properties_item import BaseEmployeeCustomPropertiesItem - from ..models.status_type_0 import StatusType0 - - d = src_dict.copy() - id = d.pop("id", UNSET) - - first_name = d.pop("first_name", UNSET) - - last_name = d.pop("last_name", UNSET) - - nickname = d.pop("nickname", UNSET) - - email = d.pop("email", UNSET) - - phone_number = d.pop("phone_number", UNSET) - - department = d.pop("department", UNSET) - - role = d.pop("role", UNSET) - - suspended = d.pop("suspended", UNSET) - - invite_status = d.pop("invite_status", UNSET) - - list_tags = cast(list[str], d.pop("list_tags", UNSET)) - - custom_properties = [] - _custom_properties = d.pop("custom_properties", UNSET) - for custom_properties_item_data in _custom_properties or []: - custom_properties_item = BaseEmployeeCustomPropertiesItem.from_dict(custom_properties_item_data) - - custom_properties.append(custom_properties_item) - - bot = d.pop("bot", UNSET) - - def _parse_user_status(data: object) -> Union["StatusType0", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - componentsschemas_status_type_0 = StatusType0.from_dict(data) - - return componentsschemas_status_type_0 - except: # noqa: E722 - pass - return cast(Union["StatusType0", None, Unset], data) - - user_status = _parse_user_status(d.pop("user_status", UNSET)) - - title = d.pop("title", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - time_zone = d.pop("time_zone", UNSET) - - def _parse_image_url(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - image_url = _parse_image_url(d.pop("image_url", UNSET)) - - employee = cls( - id=id, - first_name=first_name, - last_name=last_name, - nickname=nickname, - email=email, - phone_number=phone_number, - department=department, - role=role, - suspended=suspended, - invite_status=invite_status, - list_tags=list_tags, - custom_properties=custom_properties, - bot=bot, - user_status=user_status, - title=title, - created_at=created_at, - time_zone=time_zone, - image_url=image_url, - ) - - employee.additional_properties = d - return employee - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py deleted file mode 100644 index e9e73d2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error_payload import ErrorPayload - - -T = TypeVar("T", bound="Error") - - -@_attrs_define -class Error: - """ - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, ErrorPayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "ErrorPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error_payload import ErrorPayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, ErrorPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = ErrorPayload.from_dict(_payload) - - error = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - error.additional_properties = d - return error - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py deleted file mode 100644 index 9133249..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/error_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="ErrorPayload") - - -@_attrs_define -class ErrorPayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error_payload = cls() - - error_payload.additional_properties = d - return error_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py deleted file mode 100644 index 52b0dee..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code.py +++ /dev/null @@ -1,108 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.errors_code_payload import ErrorsCodePayload - - -T = TypeVar("T", bound="ErrorsCode") - - -@_attrs_define -class ErrorsCode: - """Bad Request - - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, ErrorsCodePayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "ErrorsCodePayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.errors_code_payload import ErrorsCodePayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, ErrorsCodePayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = ErrorsCodePayload.from_dict(_payload) - - errors_code = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - errors_code.additional_properties = d - return errors_code - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py deleted file mode 100644 index 8128de2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/errors_code_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="ErrorsCodePayload") - - -@_attrs_define -class ErrorsCodePayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - errors_code_payload = cls() - - errors_code_payload.additional_properties = d - return errors_code_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py deleted file mode 100644 index 5bb1dc4..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/file_response.py +++ /dev/null @@ -1,130 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="FileResponse") - - -@_attrs_define -class FileResponse: - """ - Attributes: - content_disposition (Union[Unset, str]): - acl (Union[Unset, str]): - policy (Union[Unset, str]): - x_amz_credential (Union[Unset, str]): - x_amz_algorithm (Union[Unset, str]): - x_amz_date (Union[Unset, str]): - x_amz_signature (Union[Unset, str]): - key (Union[Unset, str]): - direct_url (Union[Unset, str]): - """ - - content_disposition: Union[Unset, str] = UNSET - acl: Union[Unset, str] = UNSET - policy: Union[Unset, str] = UNSET - x_amz_credential: Union[Unset, str] = UNSET - x_amz_algorithm: Union[Unset, str] = UNSET - x_amz_date: Union[Unset, str] = UNSET - x_amz_signature: Union[Unset, str] = UNSET - key: Union[Unset, str] = UNSET - direct_url: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - content_disposition = self.content_disposition - - acl = self.acl - - policy = self.policy - - x_amz_credential = self.x_amz_credential - - x_amz_algorithm = self.x_amz_algorithm - - x_amz_date = self.x_amz_date - - x_amz_signature = self.x_amz_signature - - key = self.key - - direct_url = self.direct_url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if content_disposition is not UNSET: - field_dict["Content-Disposition"] = content_disposition - if acl is not UNSET: - field_dict["acl"] = acl - if policy is not UNSET: - field_dict["policy"] = policy - if x_amz_credential is not UNSET: - field_dict["x-amz-credential"] = x_amz_credential - if x_amz_algorithm is not UNSET: - field_dict["x-amz-algorithm"] = x_amz_algorithm - if x_amz_date is not UNSET: - field_dict["x-amz-date"] = x_amz_date - if x_amz_signature is not UNSET: - field_dict["x-amz-signature"] = x_amz_signature - if key is not UNSET: - field_dict["key"] = key - if direct_url is not UNSET: - field_dict["direct_url"] = direct_url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - content_disposition = d.pop("Content-Disposition", UNSET) - - acl = d.pop("acl", UNSET) - - policy = d.pop("policy", UNSET) - - x_amz_credential = d.pop("x-amz-credential", UNSET) - - x_amz_algorithm = d.pop("x-amz-algorithm", UNSET) - - x_amz_date = d.pop("x-amz-date", UNSET) - - x_amz_signature = d.pop("x-amz-signature", UNSET) - - key = d.pop("key", UNSET) - - direct_url = d.pop("direct_url", UNSET) - - file_response = cls( - content_disposition=content_disposition, - acl=acl, - policy=policy, - x_amz_credential=x_amz_credential, - x_amz_algorithm=x_amz_algorithm, - x_amz_date=x_amz_date, - x_amz_signature=x_amz_signature, - key=key, - direct_url=direct_url, - ) - - file_response.additional_properties = d - return file_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py deleted file mode 100644 index 274ed8c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.chat import Chat - - -T = TypeVar("T", bound="GetChatResponse200") - - -@_attrs_define -class GetChatResponse200: - """ - Attributes: - data (Union[Unset, Chat]): Беседа или канал - """ - - data: Union[Unset, "Chat"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.chat import Chat - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Chat] - if isinstance(_data, Unset): - data = UNSET - else: - data = Chat.from_dict(_data) - - get_chat_response_200 = cls( - data=data, - ) - - get_chat_response_200.additional_properties = d - return get_chat_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py deleted file mode 100644 index 6aaf8b1..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chat_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="GetChatResponse404") - - -@_attrs_define -class GetChatResponse404: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - get_chat_response_404 = cls( - errors=errors, - ) - - get_chat_response_404.additional_properties = d - return get_chat_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py deleted file mode 100644 index b76cb4d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_availability.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class GetChatsAvailability(str, Enum): - IS_MEMBER = "is_member" - PUBLIC = "public" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py deleted file mode 100644 index 3917a9f..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.chat import Chat - - -T = TypeVar("T", bound="GetChatsResponse200") - - -@_attrs_define -class GetChatsResponse200: - """ - Attributes: - data (Union[Unset, list['Chat']]): - """ - - data: Union[Unset, list["Chat"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.chat import Chat - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Chat.from_dict(data_item_data) - - data.append(data_item) - - get_chats_response_200 = cls( - data=data, - ) - - get_chats_response_200.additional_properties = d - return get_chats_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py deleted file mode 100644 index 005a6a3..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_400.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.errors_code import ErrorsCode - - -T = TypeVar("T", bound="GetChatsResponse400") - - -@_attrs_define -class GetChatsResponse400: - """ - Attributes: - errors (Union[Unset, ErrorsCode]): Bad Request - """ - - errors: Union[Unset, "ErrorsCode"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.errors, Unset): - errors = self.errors.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.errors_code import ErrorsCode - - d = src_dict.copy() - _errors = d.pop("errors", UNSET) - errors: Union[Unset, ErrorsCode] - if isinstance(_errors, Unset): - errors = UNSET - else: - errors = ErrorsCode.from_dict(_errors) - - get_chats_response_400 = cls( - errors=errors, - ) - - get_chats_response_400.additional_properties = d - return get_chats_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py deleted file mode 100644 index 1553a65..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="GetChatsResponse404") - - -@_attrs_define -class GetChatsResponse404: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - get_chats_response_404 = cls( - errors=errors, - ) - - get_chats_response_404.additional_properties = d - return get_chats_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py deleted file mode 100644 index 5248609..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_response_422.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.error import Error - - -T = TypeVar("T", bound="GetChatsResponse422") - - -@_attrs_define -class GetChatsResponse422: - """ - Attributes: - errors (Union[Unset, list['Error']]): - """ - - errors: Union[Unset, list["Error"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for componentsschemas_errors_item_data in self.errors: - componentsschemas_errors_item = componentsschemas_errors_item_data.to_dict() - errors.append(componentsschemas_errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.error import Error - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for componentsschemas_errors_item_data in _errors or []: - componentsschemas_errors_item = Error.from_dict(componentsschemas_errors_item_data) - - errors.append(componentsschemas_errors_item) - - get_chats_response_422 = cls( - errors=errors, - ) - - get_chats_response_422.additional_properties = d - return get_chats_response_422 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py deleted file mode 100644 index 0de410c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_chats_sortid.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class GetChatsSortid(str, Enum): - ASC = "asc" - DESC = "desc" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py deleted file mode 100644 index 93ea91d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_common_methods_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.query_common_methods import QueryCommonMethods - - -T = TypeVar("T", bound="GetCommonMethodsResponse200") - - -@_attrs_define -class GetCommonMethodsResponse200: - """ - Attributes: - data (Union[Unset, list['QueryCommonMethods']]): - """ - - data: Union[Unset, list["QueryCommonMethods"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.query_common_methods import QueryCommonMethods - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = QueryCommonMethods.from_dict(data_item_data) - - data.append(data_item) - - get_common_methods_response_200 = cls( - data=data, - ) - - get_common_methods_response_200.additional_properties = d - return get_common_methods_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py deleted file mode 100644 index b970ea8..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employee_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.employee import Employee - - -T = TypeVar("T", bound="GetEmployeeResponse200") - - -@_attrs_define -class GetEmployeeResponse200: - """ - Attributes: - data (Union[Unset, Employee]): - """ - - data: Union[Unset, "Employee"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.employee import Employee - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Employee] - if isinstance(_data, Unset): - data = UNSET - else: - data = Employee.from_dict(_data) - - get_employee_response_200 = cls( - data=data, - ) - - get_employee_response_200.additional_properties = d - return get_employee_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py deleted file mode 100644 index 978802c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_employees_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.employee import Employee - - -T = TypeVar("T", bound="GetEmployeesResponse200") - - -@_attrs_define -class GetEmployeesResponse200: - """ - Attributes: - data (Union[Unset, list['Employee']]): - """ - - data: Union[Unset, list["Employee"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.employee import Employee - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Employee.from_dict(data_item_data) - - data.append(data_item) - - get_employees_response_200 = cls( - data=data, - ) - - get_employees_response_200.additional_properties = d - return get_employees_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py deleted file mode 100644 index 52837e1..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_list_message_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="GetListMessageResponse200") - - -@_attrs_define -class GetListMessageResponse200: - """ - Attributes: - data (Union[Unset, list['Message']]): - """ - - data: Union[Unset, list["Message"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Message.from_dict(data_item_data) - - data.append(data_item) - - get_list_message_response_200 = cls( - data=data, - ) - - get_list_message_response_200.additional_properties = d - return get_list_message_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py deleted file mode 100644 index eaa7bb5..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_body.py +++ /dev/null @@ -1,68 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="GetMessageReactionsBody") - - -@_attrs_define -class GetMessageReactionsBody: - """ - Attributes: - per (Union[Unset, int]): Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - Default: 50. - page (Union[Unset, int]): Номер страницы выборки (по умолчанию 1). Default: 1. - """ - - per: Union[Unset, int] = 50 - page: Union[Unset, int] = 1 - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - per = self.per - - page = self.page - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if per is not UNSET: - field_dict["per"] = per - if page is not UNSET: - field_dict["page"] = page - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - per = d.pop("per", UNSET) - - page = d.pop("page", UNSET) - - get_message_reactions_body = cls( - per=per, - page=page, - ) - - get_message_reactions_body.additional_properties = d - return get_message_reactions_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py deleted file mode 100644 index 3c50c79..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_reactions_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.reaction import Reaction - - -T = TypeVar("T", bound="GetMessageReactionsResponse200") - - -@_attrs_define -class GetMessageReactionsResponse200: - """ - Attributes: - data (Union[Unset, list['Reaction']]): - """ - - data: Union[Unset, list["Reaction"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.reaction import Reaction - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Reaction.from_dict(data_item_data) - - data.append(data_item) - - get_message_reactions_response_200 = cls( - data=data, - ) - - get_message_reactions_response_200.additional_properties = d - return get_message_reactions_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py deleted file mode 100644 index 677295d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_message_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.message import Message - - -T = TypeVar("T", bound="GetMessageResponse200") - - -@_attrs_define -class GetMessageResponse200: - """ - Attributes: - data (Union[Unset, Message]): - """ - - data: Union[Unset, "Message"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.message import Message - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Message] - if isinstance(_data, Unset): - data = UNSET - else: - data = Message.from_dict(_data) - - get_message_response_200 = cls( - data=data, - ) - - get_message_response_200.additional_properties = d - return get_message_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py deleted file mode 100644 index 7e93886..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_status_response_200.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.status_type_0 import StatusType0 - - -T = TypeVar("T", bound="GetStatusResponse200") - - -@_attrs_define -class GetStatusResponse200: - """ - Attributes: - data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. - """ - - data: Union["StatusType0", None, Unset] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.status_type_0 import StatusType0 - - data: Union[None, Unset, dict[str, Any]] - if isinstance(self.data, Unset): - data = UNSET - elif isinstance(self.data, StatusType0): - data = self.data.to_dict() - else: - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.status_type_0 import StatusType0 - - d = src_dict.copy() - - def _parse_data(data: object) -> Union["StatusType0", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - componentsschemas_status_type_0 = StatusType0.from_dict(data) - - return componentsschemas_status_type_0 - except: # noqa: E722 - pass - return cast(Union["StatusType0", None, Unset], data) - - data = _parse_data(d.pop("data", UNSET)) - - get_status_response_200 = cls( - data=data, - ) - - get_status_response_200.additional_properties = d - return get_status_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py deleted file mode 100644 index 188f734..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_200.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.tag import Tag - - -T = TypeVar("T", bound="GetTagResponse200") - - -@_attrs_define -class GetTagResponse200: - """ - Attributes: - data (Union[Unset, Tag]): Для получения тега вам необходимо знать его id и указать его в URL запроса. - """ - - data: Union[Unset, "Tag"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.data, Unset): - data = self.data.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.tag import Tag - - d = src_dict.copy() - _data = d.pop("data", UNSET) - data: Union[Unset, Tag] - if isinstance(_data, Unset): - data = UNSET - else: - data = Tag.from_dict(_data) - - get_tag_response_200 = cls( - data=data, - ) - - get_tag_response_200.additional_properties = d - return get_tag_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py deleted file mode 100644 index c3c8ead..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem - - -T = TypeVar("T", bound="GetTagResponse404") - - -@_attrs_define -class GetTagResponse404: - """ - Attributes: - errors (Union[Unset, list['GetTagResponse404ErrorsItem']]): Список ошибок. - """ - - errors: Union[Unset, list["GetTagResponse404ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tag_response_404_errors_item import GetTagResponse404ErrorsItem - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = GetTagResponse404ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - get_tag_response_404 = cls( - errors=errors, - ) - - get_tag_response_404.additional_properties = d - return get_tag_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py deleted file mode 100644 index 18649e6..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload - - -T = TypeVar("T", bound="GetTagResponse404ErrorsItem") - - -@_attrs_define -class GetTagResponse404ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): - value (Union[Unset, str]): - message (Union[Unset, str]): - code (Union[Unset, str]): - payload (Union[Unset, GetTagResponse404ErrorsItemPayload]): - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "GetTagResponse404ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tag_response_404_errors_item_payload import GetTagResponse404ErrorsItemPayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, GetTagResponse404ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = GetTagResponse404ErrorsItemPayload.from_dict(_payload) - - get_tag_response_404_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - get_tag_response_404_errors_item.additional_properties = d - return get_tag_response_404_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py deleted file mode 100644 index b6d7c6c..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tag_response_404_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="GetTagResponse404ErrorsItemPayload") - - -@_attrs_define -class GetTagResponse404ErrorsItemPayload: - """ """ - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - get_tag_response_404_errors_item_payload = cls() - - get_tag_response_404_errors_item_payload.additional_properties = d - return get_tag_response_404_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py deleted file mode 100644 index 682b3fa..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_employees_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.base_employee import BaseEmployee - - -T = TypeVar("T", bound="GetTagsEmployeesResponse200") - - -@_attrs_define -class GetTagsEmployeesResponse200: - """ - Attributes: - data (Union[Unset, list['BaseEmployee']]): - """ - - data: Union[Unset, list["BaseEmployee"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.base_employee import BaseEmployee - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = BaseEmployee.from_dict(data_item_data) - - data.append(data_item) - - get_tags_employees_response_200 = cls( - data=data, - ) - - get_tags_employees_response_200.additional_properties = d - return get_tags_employees_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py deleted file mode 100644 index 1ae18d4..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_200.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.tag import Tag - - -T = TypeVar("T", bound="GetTagsResponse200") - - -@_attrs_define -class GetTagsResponse200: - """ - Attributes: - data (Union[Unset, list['Tag']]): - """ - - data: Union[Unset, list["Tag"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - data: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.data, Unset): - data = [] - for data_item_data in self.data: - data_item = data_item_data.to_dict() - data.append(data_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.tag import Tag - - d = src_dict.copy() - data = [] - _data = d.pop("data", UNSET) - for data_item_data in _data or []: - data_item = Tag.from_dict(data_item_data) - - data.append(data_item) - - get_tags_response_200 = cls( - data=data, - ) - - get_tags_response_200.additional_properties = d - return get_tags_response_200 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py deleted file mode 100644 index 1865c60..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem - - -T = TypeVar("T", bound="GetTagsResponse400") - - -@_attrs_define -class GetTagsResponse400: - """ - Attributes: - errors (Union[Unset, list['GetTagsResponse400ErrorsItem']]): Список ошибок в запросе. - """ - - errors: Union[Unset, list["GetTagsResponse400ErrorsItem"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - errors: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.errors, Unset): - errors = [] - for errors_item_data in self.errors: - errors_item = errors_item_data.to_dict() - errors.append(errors_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if errors is not UNSET: - field_dict["errors"] = errors - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tags_response_400_errors_item import GetTagsResponse400ErrorsItem - - d = src_dict.copy() - errors = [] - _errors = d.pop("errors", UNSET) - for errors_item_data in _errors or []: - errors_item = GetTagsResponse400ErrorsItem.from_dict(errors_item_data) - - errors.append(errors_item) - - get_tags_response_400 = cls( - errors=errors, - ) - - get_tags_response_400.additional_properties = d - return get_tags_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py deleted file mode 100644 index bd7859d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload - - -T = TypeVar("T", bound="GetTagsResponse400ErrorsItem") - - -@_attrs_define -class GetTagsResponse400ErrorsItem: - """ - Attributes: - key (Union[Unset, str]): Ключ параметра, в котором произошла ошибка. - value (Union[Unset, str]): Значение ключа, вызвавшее ошибку. - message (Union[Unset, str]): Текстовое описание ошибки. - code (Union[Unset, str]): Внутренний код ошибки. - payload (Union[Unset, GetTagsResponse400ErrorsItemPayload]): Дополнительная информация об ошибке. - """ - - key: Union[Unset, str] = UNSET - value: Union[Unset, str] = UNSET - message: Union[Unset, str] = UNSET - code: Union[Unset, str] = UNSET - payload: Union[Unset, "GetTagsResponse400ErrorsItemPayload"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - key = self.key - - value = self.value - - message = self.message - - code = self.code - - payload: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.payload, Unset): - payload = self.payload.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if key is not UNSET: - field_dict["key"] = key - if value is not UNSET: - field_dict["value"] = value - if message is not UNSET: - field_dict["message"] = message - if code is not UNSET: - field_dict["code"] = code - if payload is not UNSET: - field_dict["payload"] = payload - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.get_tags_response_400_errors_item_payload import GetTagsResponse400ErrorsItemPayload - - d = src_dict.copy() - key = d.pop("key", UNSET) - - value = d.pop("value", UNSET) - - message = d.pop("message", UNSET) - - code = d.pop("code", UNSET) - - _payload = d.pop("payload", UNSET) - payload: Union[Unset, GetTagsResponse400ErrorsItemPayload] - if isinstance(_payload, Unset): - payload = UNSET - else: - payload = GetTagsResponse400ErrorsItemPayload.from_dict(_payload) - - get_tags_response_400_errors_item = cls( - key=key, - value=value, - message=message, - code=code, - payload=payload, - ) - - get_tags_response_400_errors_item.additional_properties = d - return get_tags_response_400_errors_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py deleted file mode 100644 index 2e1d941..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/get_tags_response_400_errors_item_payload.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="GetTagsResponse400ErrorsItemPayload") - - -@_attrs_define -class GetTagsResponse400ErrorsItemPayload: - """Дополнительная информация об ошибке.""" - - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - get_tags_response_400_errors_item_payload = cls() - - get_tags_response_400_errors_item_payload.additional_properties = d - return get_tags_response_400_errors_item_payload - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py deleted file mode 100644 index bb01030..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message.py +++ /dev/null @@ -1,272 +0,0 @@ -import datetime -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..models.message_entity_type import MessageEntityType -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.button import Button - from ..models.message_files_item import MessageFilesItem - from ..models.message_forwarding import MessageForwarding - from ..models.message_thread import MessageThread - - -T = TypeVar("T", bound="Message") - - -@_attrs_define -class Message: - """ - Attributes: - entity_type (Union[Unset, MessageEntityType]): Default: MessageEntityType.DISCUSSION. - entity_id (Union[Unset, int]): - content (Union[Unset, str]): - id (Union[Unset, int]): - chat_id (Union[Unset, int]): - user_id (Union[Unset, int]): - created_at (Union[Unset, datetime.datetime]): - files (Union[Unset, list['MessageFilesItem']]): - buttons (Union[Unset, list[list['Button']]]): - thread (Union['MessageThread', None, Unset]): - forwarding (Union['MessageForwarding', None, Unset]): - parent_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому написан ответ. Возвращается как - null, если сообщение не является ответом. - """ - - entity_type: Union[Unset, MessageEntityType] = MessageEntityType.DISCUSSION - entity_id: Union[Unset, int] = UNSET - content: Union[Unset, str] = UNSET - id: Union[Unset, int] = UNSET - chat_id: Union[Unset, int] = UNSET - user_id: Union[Unset, int] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - files: Union[Unset, list["MessageFilesItem"]] = UNSET - buttons: Union[Unset, list[list["Button"]]] = UNSET - thread: Union["MessageThread", None, Unset] = UNSET - forwarding: Union["MessageForwarding", None, Unset] = UNSET - parent_message_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.message_forwarding import MessageForwarding - from ..models.message_thread import MessageThread - - entity_type: Union[Unset, str] = UNSET - if not isinstance(self.entity_type, Unset): - entity_type = self.entity_type.value - - entity_id = self.entity_id - - content = self.content - - id = self.id - - chat_id = self.chat_id - - user_id = self.user_id - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - files: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.files, Unset): - files = [] - for files_item_data in self.files: - files_item = files_item_data.to_dict() - files.append(files_item) - - buttons: Union[Unset, list[list[dict[str, Any]]]] = UNSET - if not isinstance(self.buttons, Unset): - buttons = [] - for componentsschemas_buttons_item_data in self.buttons: - componentsschemas_buttons_item = [] - for componentsschemas_buttons_item_item_data in componentsschemas_buttons_item_data: - componentsschemas_buttons_item_item = componentsschemas_buttons_item_item_data.to_dict() - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - thread: Union[None, Unset, dict[str, Any]] - if isinstance(self.thread, Unset): - thread = UNSET - elif isinstance(self.thread, MessageThread): - thread = self.thread.to_dict() - else: - thread = self.thread - - forwarding: Union[None, Unset, dict[str, Any]] - if isinstance(self.forwarding, Unset): - forwarding = UNSET - elif isinstance(self.forwarding, MessageForwarding): - forwarding = self.forwarding.to_dict() - else: - forwarding = self.forwarding - - parent_message_id: Union[None, Unset, int] - if isinstance(self.parent_message_id, Unset): - parent_message_id = UNSET - else: - parent_message_id = self.parent_message_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if entity_type is not UNSET: - field_dict["entity_type"] = entity_type - if entity_id is not UNSET: - field_dict["entity_id"] = entity_id - if content is not UNSET: - field_dict["content"] = content - if id is not UNSET: - field_dict["id"] = id - if chat_id is not UNSET: - field_dict["chat_id"] = chat_id - if user_id is not UNSET: - field_dict["user_id"] = user_id - if created_at is not UNSET: - field_dict["created_at"] = created_at - if files is not UNSET: - field_dict["files"] = files - if buttons is not UNSET: - field_dict["buttons"] = buttons - if thread is not UNSET: - field_dict["thread"] = thread - if forwarding is not UNSET: - field_dict["forwarding"] = forwarding - if parent_message_id is not UNSET: - field_dict["parent_message_id"] = parent_message_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.button import Button - from ..models.message_files_item import MessageFilesItem - from ..models.message_forwarding import MessageForwarding - from ..models.message_thread import MessageThread - - d = src_dict.copy() - _entity_type = d.pop("entity_type", UNSET) - entity_type: Union[Unset, MessageEntityType] - if isinstance(_entity_type, Unset): - entity_type = UNSET - else: - entity_type = MessageEntityType(_entity_type) - - entity_id = d.pop("entity_id", UNSET) - - content = d.pop("content", UNSET) - - id = d.pop("id", UNSET) - - chat_id = d.pop("chat_id", UNSET) - - user_id = d.pop("user_id", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - files = [] - _files = d.pop("files", UNSET) - for files_item_data in _files or []: - files_item = MessageFilesItem.from_dict(files_item_data) - - files.append(files_item) - - buttons = [] - _buttons = d.pop("buttons", UNSET) - for componentsschemas_buttons_item_data in _buttons or []: - componentsschemas_buttons_item = [] - _componentsschemas_buttons_item = componentsschemas_buttons_item_data - for componentsschemas_buttons_item_item_data in _componentsschemas_buttons_item: - componentsschemas_buttons_item_item = Button.from_dict(componentsschemas_buttons_item_item_data) - - componentsschemas_buttons_item.append(componentsschemas_buttons_item_item) - - buttons.append(componentsschemas_buttons_item) - - def _parse_thread(data: object) -> Union["MessageThread", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - thread_type_0 = MessageThread.from_dict(data) - - return thread_type_0 - except: # noqa: E722 - pass - return cast(Union["MessageThread", None, Unset], data) - - thread = _parse_thread(d.pop("thread", UNSET)) - - def _parse_forwarding(data: object) -> Union["MessageForwarding", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - forwarding_type_0 = MessageForwarding.from_dict(data) - - return forwarding_type_0 - except: # noqa: E722 - pass - return cast(Union["MessageForwarding", None, Unset], data) - - forwarding = _parse_forwarding(d.pop("forwarding", UNSET)) - - def _parse_parent_message_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - parent_message_id = _parse_parent_message_id(d.pop("parent_message_id", UNSET)) - - message = cls( - entity_type=entity_type, - entity_id=entity_id, - content=content, - id=id, - chat_id=chat_id, - user_id=user_id, - created_at=created_at, - files=files, - buttons=buttons, - thread=thread, - forwarding=forwarding, - parent_message_id=parent_message_id, - ) - - message.additional_properties = d - return message - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py deleted file mode 100644 index e8a126a..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_entity_type.py +++ /dev/null @@ -1,10 +0,0 @@ -from enum import Enum - - -class MessageEntityType(str, Enum): - DISCUSSION = "discussion" - THREAD = "thread" - USER = "user" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py deleted file mode 100644 index 21509d2..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..models.message_files_item_file_type import MessageFilesItemFileType -from ..types import UNSET, Unset - -T = TypeVar("T", bound="MessageFilesItem") - - -@_attrs_define -class MessageFilesItem: - """ - Attributes: - id (Union[Unset, int]): - key (Union[Unset, str]): Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении - должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name (Union[Unset, str]): Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе - с расширением) - file_type (Union[Unset, MessageFilesItemFileType]): - url (Union[Unset, str]): Размер файла в байтах, отображаемый пользователю - """ - - id: Union[Unset, int] = UNSET - key: Union[Unset, str] = UNSET - name: Union[Unset, str] = UNSET - file_type: Union[Unset, MessageFilesItemFileType] = UNSET - url: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - key = self.key - - name = self.name - - file_type: Union[Unset, str] = UNSET - if not isinstance(self.file_type, Unset): - file_type = self.file_type.value - - url = self.url - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if key is not UNSET: - field_dict["key"] = key - if name is not UNSET: - field_dict["name"] = name - if file_type is not UNSET: - field_dict["file_type"] = file_type - if url is not UNSET: - field_dict["url"] = url - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - key = d.pop("key", UNSET) - - name = d.pop("name", UNSET) - - _file_type = d.pop("file_type", UNSET) - file_type: Union[Unset, MessageFilesItemFileType] - if isinstance(_file_type, Unset): - file_type = UNSET - else: - file_type = MessageFilesItemFileType(_file_type) - - url = d.pop("url", UNSET) - - message_files_item = cls( - id=id, - key=key, - name=name, - file_type=file_type, - url=url, - ) - - message_files_item.additional_properties = d - return message_files_item - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py deleted file mode 100644 index 1e00e5b..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_files_item_file_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class MessageFilesItemFileType(str, Enum): - FILE = "file" - IMAGE = "image" - - def __str__(self) -> str: - return str(self.value) diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py deleted file mode 100644 index 6ce981d..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_forwarding.py +++ /dev/null @@ -1,153 +0,0 @@ -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="MessageForwarding") - - -@_attrs_define -class MessageForwarding: - """ - Attributes: - original_message_id (Union[Unset, int]): Идентификатор оригинального сообщения - original_chat_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение - author_id (Union[Unset, int]): Идентификатор чата, в котором находится оригинальное сообщение - original_created_at (Union[Unset, int]): Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в - формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id (Union[None, Unset, int]): Идентификатор треда, в котором находится оригинальное сообщение. - Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id (Union[None, Unset, int]): Идентификатор сообщения, к которому был создан тред, в - котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является - комментарием в треде. - original_thread_parent_chat_id (Union[None, Unset, int]): Идентификатор чата сообщения, к которому был создан - тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является - комментарием в треде. - """ - - original_message_id: Union[Unset, int] = UNSET - original_chat_id: Union[Unset, int] = UNSET - author_id: Union[Unset, int] = UNSET - original_created_at: Union[Unset, int] = UNSET - original_thread_id: Union[None, Unset, int] = UNSET - original_thread_message_id: Union[None, Unset, int] = UNSET - original_thread_parent_chat_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - original_message_id = self.original_message_id - - original_chat_id = self.original_chat_id - - author_id = self.author_id - - original_created_at = self.original_created_at - - original_thread_id: Union[None, Unset, int] - if isinstance(self.original_thread_id, Unset): - original_thread_id = UNSET - else: - original_thread_id = self.original_thread_id - - original_thread_message_id: Union[None, Unset, int] - if isinstance(self.original_thread_message_id, Unset): - original_thread_message_id = UNSET - else: - original_thread_message_id = self.original_thread_message_id - - original_thread_parent_chat_id: Union[None, Unset, int] - if isinstance(self.original_thread_parent_chat_id, Unset): - original_thread_parent_chat_id = UNSET - else: - original_thread_parent_chat_id = self.original_thread_parent_chat_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if original_message_id is not UNSET: - field_dict["original_message_id"] = original_message_id - if original_chat_id is not UNSET: - field_dict["original_chat_id"] = original_chat_id - if author_id is not UNSET: - field_dict["author_id"] = author_id - if original_created_at is not UNSET: - field_dict["original_created_at"] = original_created_at - if original_thread_id is not UNSET: - field_dict["original_thread_id"] = original_thread_id - if original_thread_message_id is not UNSET: - field_dict["original_thread_message_id"] = original_thread_message_id - if original_thread_parent_chat_id is not UNSET: - field_dict["original_thread_parent_chat_id"] = original_thread_parent_chat_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - original_message_id = d.pop("original_message_id", UNSET) - - original_chat_id = d.pop("original_chat_id", UNSET) - - author_id = d.pop("author_id", UNSET) - - original_created_at = d.pop("original_created_at", UNSET) - - def _parse_original_thread_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - original_thread_id = _parse_original_thread_id(d.pop("original_thread_id", UNSET)) - - def _parse_original_thread_message_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - original_thread_message_id = _parse_original_thread_message_id(d.pop("original_thread_message_id", UNSET)) - - def _parse_original_thread_parent_chat_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - original_thread_parent_chat_id = _parse_original_thread_parent_chat_id( - d.pop("original_thread_parent_chat_id", UNSET) - ) - - message_forwarding = cls( - original_message_id=original_message_id, - original_chat_id=original_chat_id, - author_id=author_id, - original_created_at=original_created_at, - original_thread_id=original_thread_id, - original_thread_message_id=original_thread_message_id, - original_thread_parent_chat_id=original_thread_parent_chat_id, - ) - - message_forwarding.additional_properties = d - return message_forwarding - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py deleted file mode 100644 index ddd18f0..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/message_thread.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="MessageThread") - - -@_attrs_define -class MessageThread: - """ - Attributes: - id (Union[Unset, int]): - chat_id (Union[Unset, int]): - """ - - id: Union[Unset, int] = UNSET - chat_id: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - chat_id = self.chat_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if chat_id is not UNSET: - field_dict["chat_id"] = chat_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - chat_id = d.pop("chat_id", UNSET) - - message_thread = cls( - id=id, - chat_id=chat_id, - ) - - message_thread.additional_properties = d - return message_thread - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py deleted file mode 100644 index c24e928..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/not_found.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="NotFound") - - -@_attrs_define -class NotFound: - """Объект не найден - - Attributes: - detail (Union[Unset, str]): Описание ошибки Example: Страница не найдена.. - """ - - detail: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - detail = self.detail - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if detail is not UNSET: - field_dict["detail"] = detail - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - detail = d.pop("detail", UNSET) - - not_found = cls( - detail=detail, - ) - - not_found.additional_properties = d - return not_found - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py deleted file mode 100644 index 620f8dc..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_members_to_chats_body.py +++ /dev/null @@ -1,69 +0,0 @@ -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMembersToChatsBody") - - -@_attrs_define -class PostMembersToChatsBody: - """ - Attributes: - member_ids (list[int]): Example: [186, 187]. - silent (Union[Unset, bool]): - """ - - member_ids: list[int] - silent: Union[Unset, bool] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - member_ids = self.member_ids - - silent = self.silent - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "member_ids": member_ids, - } - ) - if silent is not UNSET: - field_dict["silent"] = silent - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - member_ids = cast(list[int], d.pop("member_ids")) - - silent = d.pop("silent", UNSET) - - post_members_to_chats_body = cls( - member_ids=member_ids, - silent=silent, - ) - - post_members_to_chats_body.additional_properties = d - return post_members_to_chats_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py deleted file mode 100644 index fffa22a..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_body.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="PostMessageReactionsBody") - - -@_attrs_define -class PostMessageReactionsBody: - """ - Attributes: - code (str): Emoji в строковом формате для добавления реакции. - """ - - code: str - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - code = self.code - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "code": code, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - code = d.pop("code") - - post_message_reactions_body = cls( - code=code, - ) - - post_message_reactions_body.additional_properties = d - return post_message_reactions_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py deleted file mode 100644 index 50b0078..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_400.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMessageReactionsResponse400") - - -@_attrs_define -class PostMessageReactionsResponse400: - """ - Attributes: - error (Union[Unset, str]): Описание ошибки. - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_message_reactions_response_400 = cls( - error=error, - ) - - post_message_reactions_response_400.additional_properties = d - return post_message_reactions_response_400 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py deleted file mode 100644 index cd52780..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_403.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMessageReactionsResponse403") - - -@_attrs_define -class PostMessageReactionsResponse403: - """ - Attributes: - error (Union[Unset, str]): Описание ошибки. - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_message_reactions_response_403 = cls( - error=error, - ) - - post_message_reactions_response_403.additional_properties = d - return post_message_reactions_response_403 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py deleted file mode 100644 index 1a26c89..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_message_reactions_response_404.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="PostMessageReactionsResponse404") - - -@_attrs_define -class PostMessageReactionsResponse404: - """ - Attributes: - error (Union[Unset, str]): Сообщение не найдено. - """ - - error: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if error is not UNSET: - field_dict["error"] = error - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - error = d.pop("error", UNSET) - - post_message_reactions_response_404 = cls( - error=error, - ) - - post_message_reactions_response_404.additional_properties = d - return post_message_reactions_response_404 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py deleted file mode 100644 index 23040f4..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/post_tags_to_chats_body.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="PostTagsToChatsBody") - - -@_attrs_define -class PostTagsToChatsBody: - """ - Attributes: - group_tag_ids (list[int]): Example: [86, 18]. - """ - - group_tag_ids: list[int] - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - group_tag_ids = self.group_tag_ids - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "group_tag_ids": group_tag_ids, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - group_tag_ids = cast(list[int], d.pop("group_tag_ids")) - - post_tags_to_chats_body = cls( - group_tag_ids=group_tag_ids, - ) - - post_tags_to_chats_body.additional_properties = d - return post_tags_to_chats_body - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py deleted file mode 100644 index a34d4e0..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/put_status_response_201.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.status_type_0 import StatusType0 - - -T = TypeVar("T", bound="PutStatusResponse201") - - -@_attrs_define -class PutStatusResponse201: - """ - Attributes: - data (Union['StatusType0', None, Unset]): Статус. Возвращается как null, если статус не установлен. - """ - - data: Union["StatusType0", None, Unset] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - from ..models.status_type_0 import StatusType0 - - data: Union[None, Unset, dict[str, Any]] - if isinstance(self.data, Unset): - data = UNSET - elif isinstance(self.data, StatusType0): - data = self.data.to_dict() - else: - data = self.data - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if data is not UNSET: - field_dict["data"] = data - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.status_type_0 import StatusType0 - - d = src_dict.copy() - - def _parse_data(data: object) -> Union["StatusType0", None, Unset]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, dict): - raise TypeError() - componentsschemas_status_type_0 = StatusType0.from_dict(data) - - return componentsschemas_status_type_0 - except: # noqa: E722 - pass - return cast(Union["StatusType0", None, Unset], data) - - data = _parse_data(d.pop("data", UNSET)) - - put_status_response_201 = cls( - data=data, - ) - - put_status_response_201.additional_properties = d - return put_status_response_201 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py deleted file mode 100644 index f3e1788..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_chat.py +++ /dev/null @@ -1,91 +0,0 @@ -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryChat") - - -@_attrs_define -class QueryChat: - """Собранный объект параметров создаваемой беседы или канала - - Attributes: - name (str): Название Example: 🤿 aqua. - member_ids (Union[Unset, list[int]]): Массив идентификаторов пользователей, которые станут участниками Example: - [186, 187]. - channel (Union[Unset, bool]): Тип: беседа (по умолчанию, false) или канал (true) Example: True. - public (Union[Unset, bool]): Доступ: закрытый (по умолчанию, false) или открытый (true) - """ - - name: str - member_ids: Union[Unset, list[int]] = UNSET - channel: Union[Unset, bool] = UNSET - public: Union[Unset, bool] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - name = self.name - - member_ids: Union[Unset, list[int]] = UNSET - if not isinstance(self.member_ids, Unset): - member_ids = self.member_ids - - channel = self.channel - - public = self.public - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "name": name, - } - ) - if member_ids is not UNSET: - field_dict["member_ids"] = member_ids - if channel is not UNSET: - field_dict["channel"] = channel - if public is not UNSET: - field_dict["public"] = public - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - name = d.pop("name") - - member_ids = cast(list[int], d.pop("member_ids", UNSET)) - - channel = d.pop("channel", UNSET) - - public = d.pop("public", UNSET) - - query_chat = cls( - name=name, - member_ids=member_ids, - channel=channel, - public=public, - ) - - query_chat.additional_properties = d - return query_chat - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py deleted file mode 100644 index f575b43..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_common_methods.py +++ /dev/null @@ -1,77 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryCommonMethods") - - -@_attrs_define -class QueryCommonMethods: - """получение списка актульных полей сущности. - - Attributes: - id (Union[Unset, int]): Название поля Example: 1. - name (Union[Unset, str]): Идентификатор поля Example: Дата рождения. - data_type (Union[Unset, str]): тип поля (string, number, date или link) Example: number. - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - data_type: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - data_type = self.data_type - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if data_type is not UNSET: - field_dict["data_type"] = data_type - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - data_type = d.pop("data_type", UNSET) - - query_common_methods = cls( - id=id, - name=name, - data_type=data_type, - ) - - query_common_methods.additional_properties = d - return query_common_methods - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py deleted file mode 100644 index 885c9fc..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.query_status_status import QueryStatusStatus - - -T = TypeVar("T", bound="QueryStatus") - - -@_attrs_define -class QueryStatus: - """ - Attributes: - status (Union[Unset, QueryStatusStatus]): Собранный объект параметров нового статуса - """ - - status: Union[Unset, "QueryStatusStatus"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - status: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.status, Unset): - status = self.status.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if status is not UNSET: - field_dict["status"] = status - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - from ..models.query_status_status import QueryStatusStatus - - d = src_dict.copy() - _status = d.pop("status", UNSET) - status: Union[Unset, QueryStatusStatus] - if isinstance(_status, Unset): - status = UNSET - else: - status = QueryStatusStatus.from_dict(_status) - - query_status = cls( - status=status, - ) - - query_status.additional_properties = d - return query_status - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py deleted file mode 100644 index 48858ea..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/query_status_status.py +++ /dev/null @@ -1,102 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryStatusStatus") - - -@_attrs_define -class QueryStatusStatus: - """Собранный объект параметров нового статуса - - Attributes: - emoji (str): Emoji символ статуса - title (str): Текст статуса - expires_at (Union[None, Unset, datetime.datetime]): Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM- - DDThh:mm:ss.sssZ - """ - - emoji: str - title: str - expires_at: Union[None, Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - emoji = self.emoji - - title = self.title - - expires_at: Union[None, Unset, str] - if isinstance(self.expires_at, Unset): - expires_at = UNSET - elif isinstance(self.expires_at, datetime.datetime): - expires_at = self.expires_at.isoformat() - else: - expires_at = self.expires_at - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "emoji": emoji, - "title": title, - } - ) - if expires_at is not UNSET: - field_dict["expires_at"] = expires_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - emoji = d.pop("emoji") - - title = d.pop("title") - - def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - expires_at_type_0 = isoparse(data) - - return expires_at_type_0 - except: # noqa: E722 - pass - return cast(Union[None, Unset, datetime.datetime], data) - - expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) - - query_status_status = cls( - emoji=emoji, - title=title, - expires_at=expires_at, - ) - - query_status_status.additional_properties = d - return query_status_status - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py deleted file mode 100644 index de28f69..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/reaction.py +++ /dev/null @@ -1,86 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Reaction") - - -@_attrs_define -class Reaction: - """ - Attributes: - user_id (Union[Unset, int]): Идентификатор пользователя, оставившего реакцию. - created_at (Union[Unset, datetime.datetime]): Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY- - MM-DDThh:mm:ss.sssZ. - code (Union[Unset, str]): Emoji символ реакции. - """ - - user_id: Union[Unset, int] = UNSET - created_at: Union[Unset, datetime.datetime] = UNSET - code: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - user_id = self.user_id - - created_at: Union[Unset, str] = UNSET - if not isinstance(self.created_at, Unset): - created_at = self.created_at.isoformat() - - code = self.code - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if user_id is not UNSET: - field_dict["user_id"] = user_id - if created_at is not UNSET: - field_dict["created_at"] = created_at - if code is not UNSET: - field_dict["code"] = code - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - user_id = d.pop("user_id", UNSET) - - _created_at = d.pop("created_at", UNSET) - created_at: Union[Unset, datetime.datetime] - if isinstance(_created_at, Unset): - created_at = UNSET - else: - created_at = isoparse(_created_at) - - code = d.pop("code", UNSET) - - reaction = cls( - user_id=user_id, - created_at=created_at, - code=code, - ) - - reaction.additional_properties = d - return reaction - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py deleted file mode 100644 index 8997cfe..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/status_type_0.py +++ /dev/null @@ -1,101 +0,0 @@ -import datetime -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="StatusType0") - - -@_attrs_define -class StatusType0: - """Статус. Возвращается как null, если статус не установлен. - - Attributes: - emoji (Union[Unset, str]): Emoji символ статуса - title (Union[Unset, str]): Текст статуса - expires_at (Union[None, Unset, datetime.datetime]): Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM- - DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - """ - - emoji: Union[Unset, str] = UNSET - title: Union[Unset, str] = UNSET - expires_at: Union[None, Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - emoji = self.emoji - - title = self.title - - expires_at: Union[None, Unset, str] - if isinstance(self.expires_at, Unset): - expires_at = UNSET - elif isinstance(self.expires_at, datetime.datetime): - expires_at = self.expires_at.isoformat() - else: - expires_at = self.expires_at - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if emoji is not UNSET: - field_dict["emoji"] = emoji - if title is not UNSET: - field_dict["title"] = title - if expires_at is not UNSET: - field_dict["expires_at"] = expires_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - emoji = d.pop("emoji", UNSET) - - title = d.pop("title", UNSET) - - def _parse_expires_at(data: object) -> Union[None, Unset, datetime.datetime]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - expires_at_type_0 = isoparse(data) - - return expires_at_type_0 - except: # noqa: E722 - pass - return cast(Union[None, Unset, datetime.datetime], data) - - expires_at = _parse_expires_at(d.pop("expires_at", UNSET)) - - status_type_0 = cls( - emoji=emoji, - title=title, - expires_at=expires_at, - ) - - status_type_0.additional_properties = d - return status_type_0 - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py deleted file mode 100644 index 6504540..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/models/tag.py +++ /dev/null @@ -1,77 +0,0 @@ -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="Tag") - - -@_attrs_define -class Tag: - """Для получения тега вам необходимо знать его id и указать его в URL запроса. - - Attributes: - id (Union[Unset, int]): Идентификатор тега - name (Union[Unset, str]): Название тега - users_count (Union[Unset, int]): Количество сотрудников, которые имеют этот тег - """ - - id: Union[Unset, int] = UNSET - name: Union[Unset, str] = UNSET - users_count: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - name = self.name - - users_count = self.users_count - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if name is not UNSET: - field_dict["name"] = name - if users_count is not UNSET: - field_dict["users_count"] = users_count - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: - d = src_dict.copy() - id = d.pop("id", UNSET) - - name = d.pop("name", UNSET) - - users_count = d.pop("users_count", UNSET) - - tag = cls( - id=id, - name=name, - users_count=users_count, - ) - - tag.additional_properties = d - return tag - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed deleted file mode 100644 index 1aad327..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/py.typed +++ /dev/null @@ -1 +0,0 @@ -# Marker file for PEP 561 \ No newline at end of file diff --git a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py b/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py deleted file mode 100644 index b9ed58b..0000000 --- a/src/generator1/pachca_servis/pachca_api_open_api_3_0_client/types.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Contains some shared types for properties""" - -from collections.abc import MutableMapping -from http import HTTPStatus -from typing import BinaryIO, Generic, Literal, Optional, TypeVar - -from attrs import define - - -class Unset: - def __bool__(self) -> Literal[False]: - return False - - -UNSET: Unset = Unset() - -FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] - - -@define -class File: - """Contains information for file uploads""" - - payload: BinaryIO - file_name: Optional[str] = None - mime_type: Optional[str] = None - - def to_tuple(self) -> FileJsonType: - """Return a tuple representation that httpx will accept for multipart/form-data""" - return self.file_name, self.payload, self.mime_type - - -T = TypeVar("T") - - -@define -class Response(Generic[T]): - """A response from an endpoint""" - - status_code: HTTPStatus - content: bytes - headers: MutableMapping[str, str] - parsed: Optional[T] - - -__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/src/generator1/pachca_servis/pyproject.toml b/src/generator1/pachca_servis/pyproject.toml deleted file mode 100644 index 29f8de8..0000000 --- a/src/generator1/pachca_servis/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[tool.poetry] -name = "pachca-api-open-api-3-0-client" -version = "3.0.3" -description = "A client library for accessing PachcaAPI - OpenAPI 3.0" -authors = [] -readme = "README.md" -packages = [ - {include = "pachca_api_open_api_3_0_client"}, -] -include = ["CHANGELOG.md", "pachca_api_open_api_3_0_client/py.typed"] - - -[tool.poetry.dependencies] -python = "^3.9" -httpx = ">=0.20.0,<0.28.0" -attrs = ">=21.3.0" -python-dateutil = "^2.8.0" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.ruff] -line-length = 120 - -[tool.ruff.lint] -select = ["F", "I", "UP"] diff --git a/src/generator1/script.py b/src/generator1/script.py index 7cec085..81d609d 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -45,7 +45,7 @@ def get_all_api_functions_and_imports(api_dir): return all_functions, all_imports -api_dir = "./pachca_servis/pachca_api_open_api_3_0_client/api" +api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" endpoints, imports = get_all_api_functions_and_imports(api_dir) env = Environment( @@ -54,7 +54,7 @@ def get_all_api_functions_and_imports(api_dir): client_template = env.get_template('client.py.jinja') -client_path = './pachca_servis/pachca_api_open_api_3_0_client/client.py' +client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' with open(client_path, mode='w', encoding="utf-8") as file: unique_imports = list(set(imports)) @@ -81,13 +81,13 @@ def get_all_api_functions_and_imports(api_dir): file.write(client_template.render(endpoints=endpoints)) # cli_servis_template = env.get_template('client_servis.py.jinja') -# cli_servis_path = './pachca_servis/pachca_api_open_api_3_0_client/client_servis.py' +cli_servis_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client_serv.py' # with open(cli_servis_path, mode='w', encoding="utf-8") as file: # file.write(cli_servis_template.render()) # cli_servis_path = './pachca_servis/pachca_api_open_api_3_0_client/client_servis.py' # Определяем путь к файлу, который нужно скопировать source_file = os.path.join(os.path.dirname(__file__), '..', 'generator1', 'client_servis.py') -cli_servis_path = os.path.join(os.path.dirname(__file__), 'pachca_servis', 'pachca_api_open_api_3_0_client', 'client_serv.py') +# cli_servis_path = os.path.join(os.path.dirname(__file__), 'pachca_servis', 'pachca_api_open_api_3_0_client', 'client_serv.py') # import pdb;pdb.set_trace()# Копируем файл shutil.copy(source_file, cli_servis_path) From e83fa1e4cbb20190c0d94aa65b93ce871eee6c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 15:10:00 +0300 Subject: [PATCH 117/296] requirments and Client fixes --- src/generator1/pachca.py | 1 - src/generator1/requirements.txt | 21 +-- src/generator1/script.py | 94 ------------ src/generator1/templates/client.py.jinja | 141 ------------------ .../templates/package_init.py.jinja | 6 + 5 files changed, 7 insertions(+), 256 deletions(-) create mode 100644 src/generator1/templates/package_init.py.jinja diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index bf5bef7..8c1f67a 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -17,7 +17,6 @@ async def main() -> None: """ Функция теста эндпоинтов """ - task1 = asyncio.create_task(pachca.createChat(body=chat_body)) task2 = asyncio.create_task(pachca.getEmployees()) diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index ee90ff3..ed4d7aa 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -1,29 +1,10 @@ -annotated-types==0.7.0 anyio==4.7.0 attrs==24.3.0 -certifi==2024.12.14 -click==8.1.7 -colorama==0.4.6 -h11==0.14.0 httpcore==1.0.7 httpx==0.27.2 -idna==3.10 Jinja2==3.1.4 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mdurl==0.1.2 openapi-python-client==0.22.0 -pydantic==2.10.4 -pydantic_core==2.27.2 -Pygments==2.18.0 -python-dateutil==2.9.0.post0 PyYAML==6.0.2 -rich==13.9.4 ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 -ruff==0.8.4 -shellingham==1.5.4 -six==1.17.0 -sniffio==1.3.1 -typer==0.13.1 -typing_extensions==4.12.2 +typing_extensions==4.12.2 \ No newline at end of file diff --git a/src/generator1/script.py b/src/generator1/script.py index 3b71cab..01da345 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,97 +1,3 @@ -# import ast -# import os -# import subprocess - -# import yaml -# from jinja2 import Environment, FileSystemLoader - - -# def extract_functions_and_imports_from_file(file_path) -> None: -# with open(file_path, "r", encoding="utf-8") as file: -# tree = ast.parse(file.read()) - -# functions = [] -# imports = [] - -# for node in ast.walk(tree): -# if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, -# ast.FunctionDef): -# functions.append(ast.unparse(node)) -# elif isinstance(node, ast.ImportFrom): -# # Убираем пробел после 'from' и обрабатываем импорты -# module = node.module if node.module else '' -# if module.startswith('.'): -# module = module[1:] # Убираем точку в начале -# for alias in node.names: -# if module == 'typing' or module == 'http': -# imports.append(f"from {module} import {alias.name}") -# else: -# imports.append(f"from .{module} import {alias.name}") - -# return functions, imports - - -# def get_all_api_functions_and_imports(api_dir): -# all_functions = [] -# all_imports = [] -# for root, _, files in os.walk(api_dir): -# for file in files: -# if file.endswith(".py"): -# file_path = os.path.join(root, file) -# functions, imports = extract_functions_and_imports_from_file(file_path) -# all_functions.extend(functions) -# all_imports.extend(imports) -# return all_functions, all_imports - - -# def create_modified_openapi_yaml(input_path, output_path): -# with open(input_path, "r", encoding="utf-8") as file: -# openapi_data = yaml.safe_load(file) -# base_url = openapi_data.get("servers", [{}])[0].get("url") -# openapi_data["x-base-url"] = base_url - -# with open(output_path, "w", encoding="utf-8") as file: -# yaml.dump(openapi_data, file) - -# return base_url - - -# def generate_client(openapi_path, templates_path): -# command = [ -# "openapi-python-client", -# "generate", -# "--path", openapi_path, -# "--custom-template-path", templates_path, -# "--overwrite" -# ] -# subprocess.run(command, check=True) - - -# def process_generated_client(api_dir, client_template_path, client_output_path, base_url): -# endpoints, imports = get_all_api_functions_and_imports(api_dir) - -# env = Environment(loader=FileSystemLoader('templates')) -# client_template = env.get_template(client_template_path) - -# with open(client_output_path, mode='w', encoding="utf-8") as file: -# # Объединяем импорты в одну строку -# unique_imports = list(set(imports)) # Убираем дубликаты -# file.write("\n".join(unique_imports) + "\n\n") # Записываем импорты в файл -# file.write(client_template.render(endpoints=endpoints, base_url=base_url)) - - -# openapi_input_path = "openapi.yaml" -# openapi_modified_path = "openapi_modified.yaml" -# templates_path = "./templates" -# api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -# client_template_name = "client.py.jinja" -# client_output_path = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" - -# # Выполнение шагов -# base_url = create_modified_openapi_yaml(openapi_input_path, openapi_modified_path) -# generate_client(openapi_modified_path, templates_path) -# process_generated_client(api_dir, client_template_name, client_output_path, base_url) - import ast import os diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index e35a6ec..2ba67a3 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -7,146 +7,6 @@ import httpx {% from "macros/client_macros.py.jinja" import httpx_args_docstring %} -@define -class Client: - """A class for keeping track of data related to the API - -{% macro httpx_args_docstring() %} - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. -{% endmacro %} -{{ httpx_args_docstring() }} - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ -{% macro attributes() %} - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field( - default="{{ base_url }}", - kw_only=True, - alias="base_url" - ) - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) -{% endmacro %}{{ attributes() }} -{% macro builders(self) %} - def with_headers(self, headers: dict[str, str]) -> "{{ self }}": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "{{ self }}": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "{{ self }}": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) -{% endmacro %}{{ builders("Client") }} -{% macro httpx_stuff(name, custom_constructor=None) %} - def set_httpx_client(self, client: httpx.Client) -> "{{ name }}": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - {% if custom_constructor %} - {{ custom_constructor | indent(12) }} - {% endif %} - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "{{ name }}": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "{{ name }}": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - {% if custom_constructor %} - {{ custom_constructor | indent(12) }} - {% endif %} - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "{{ name }}": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) -{% endmacro %}{{ httpx_stuff("Client") }} @define class AuthenticatedClient: @@ -269,7 +129,6 @@ class Pachca: def __init__(self, token): self.client = AuthenticatedClient(token=token) - self.base_url = '{{ base_url }}' {% if endpoints %} {% for endpoint in endpoints %} {{ endpoint | indent(4, first=Fasle) }} diff --git a/src/generator1/templates/package_init.py.jinja b/src/generator1/templates/package_init.py.jinja new file mode 100644 index 0000000..db2297b --- /dev/null +++ b/src/generator1/templates/package_init.py.jinja @@ -0,0 +1,6 @@ +{% from "helpers.jinja" import safe_docstring %} + +{{ safe_docstring(package_description) }} +from .client import AuthenticatedClient #noqa + +__all__ = "AuthenticatedClient" From 87a5b8b66815f02dc480752592f4f80f8f394c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 16:43:13 +0300 Subject: [PATCH 118/296] modified_openapi_delete --- src/generator1/openapi_modified.yaml | 3162 -------------------------- 1 file changed, 3162 deletions(-) delete mode 100644 src/generator1/openapi_modified.yaml diff --git a/src/generator1/openapi_modified.yaml b/src/generator1/openapi_modified.yaml deleted file mode 100644 index 90c74d0..0000000 --- a/src/generator1/openapi_modified.yaml +++ /dev/null @@ -1,3162 +0,0 @@ -components: - schemas: - BadRequest: - properties: - error: - type: string - message: - type: string - type: object - BaseEmployee: - description: "\u0411\u0430\u0437\u043E\u0432\u044B\u0439 \u043A\u043B\u0430\u0441\ - \u0441 \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0430." - properties: - bot: - description: "\u0422\u0438\u043F: \u043F\u043E\u043B\u044C\u0437\u043E\u0432\ - \u0430\u0442\u0435\u043B\u044C (false) \u0438\u043B\u0438 \u0431\u043E\ - \u0442 (true)\n" - type: boolean - custom_properties: - description: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\ - \u044C\u043D\u044B\u0435 \u043F\u043E\u043B\u044F \u0441\u043E\u0442\u0440\ - \u0443\u0434\u043D\u0438\u043A\u0430" - items: - properties: - data_type: - description: "\u0422\u0438\u043F \u043F\u043E\u043B\u044F (string,\ - \ number, date \u0438\u043B\u0438 link)" - type: string - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044F" - type: integer - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043F\ - \u043E\u043B\u044F" - type: string - value: - description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435" - type: string - type: object - type: array - department: - description: "\u0414\u0435\u043F\u0430\u0440\u0442\u0430\u043C\u0435\u043D\ - \u0442" - type: string - email: - description: "\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\ - \u044F \u043F\u043E\u0447\u0442\u0430" - type: string - first_name: - description: "\u0418\u043C\u044F" - type: string - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\ - \u0435\u043B\u044F" - example: 1 - type: integer - invite_status: - description: "\u0421\u0442\u0430\u0442\u0443\u0441 \u043F\u0440\u0438\u0433\ - \u043B\u0430\u0448\u0435\u043D\u0438\u044F: confirmed (\u043F\u0440\u0438\ - \u043D\u044F\u0442\u043E), sent (\u043E\u0442\u043F\u0440\u0430\u0432\u043B\ - \u0435\u043D\u043E)\n" - type: string - last_name: - description: "\u0424\u0430\u043C\u0438\u043B\u0438\u044F" - type: string - list_tags: - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0442\u0435\u0433\u043E\ - \u0432, \u043F\u0440\u0438\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0445\ - \ \u043A \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0443" - items: - type: string - type: array - nickname: - description: "\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\ - \u0430\u0442\u0435\u043B\u044F" - type: string - phone_number: - description: "\u0422\u0435\u043B\u0435\u0444\u043E\u043D" - type: string - role: - description: "\u0423\u0440\u043E\u0432\u0435\u043D\u044C \u0434\u043E\u0441\ - \u0442\u0443\u043F\u0430: admin (\u0430\u0434\u043C\u0438\u043D\u0438\u0441\ - \u0442\u0440\u0430\u0442\u043E\u0440), user (\u0441\u043E\u0442\u0440\u0443\ - \u0434\u043D\u0438\u043A), multi_guest (\u043C\u0443\u043B\u044C\u0442\ - \u0438-\u0433\u043E\u0441\u0442\u044C)\n" - type: string - suspended: - description: "\u0414\u0435\u0430\u043A\u0442\u0438\u0432\u0430\u0446\u0438\ - \u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ - \u044F. \u041F\u0440\u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0438\ - \ true \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ - \u044C \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0434\u0435\u0430\ - \u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\ - \u043C.\n" - type: boolean - type: object - Buttons: - items: - items: - minProperties: 2 - properties: - data: - maxLength: 255 - title: Data - type: string - text: - maxLength: 255 - title: Text - type: string - url: - title: Url - type: string - required: - - text - title: Button - type: object - maxItems: 8 - title: Row Buttons - type: array - maxItems: 100 - title: Message Buttons - type: array - Chat: - description: "\u0411\u0435\u0441\u0435\u0434\u0430 \u0438\u043B\u0438 \u043A\ - \u0430\u043D\u0430\u043B" - properties: - channel: - description: "\u0422\u0438\u043F: \u0431\u0435\u0441\u0435\u0434\u0430 (false)\ - \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B (true)" - example: true - type: boolean - created_at: - description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F\ - \ \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u0431\u0435\u0441\u0435\ - \u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430 (ISO-8601,\ - \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" - example: '2021-08-28T15:56:53.000Z' - format: date-time - type: string - group_tag_ids: - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ - \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u0442\ - \u0435\u0433\u043E\u0432, \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\ - \u043E\u0432" - example: [] - items: - type: integer - type: array - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438\ - \ \u043A\u0430\u043D\u0430\u043B\u0430" - example: 334 - type: integer - last_message_at: - description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F\ - \ \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u043B\ - \u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u044F \u0432 \u0431\u0435\u0441\u0435\u0434\u0435/\u043A\u0430\ - \u043D\u0430\u043B\u0435 (ISO-8601, UTC+0) \u0432 \u0444\u043E\u0440\u043C\ - \u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" - example: '2021-08-28T15:58:13.000Z' - format: date-time - type: string - meet_room_url: - description: "\u0421\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0412\u0438\ - \u0434\u0435\u043E\u0447\u0430\u0442" - example: https://meet.pachca.com/aqua-94bb21b5 - type: string - member_ids: - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ - \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u043F\ - \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439\ - , \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u0432" - example: - - 185 - - 186 - - 187 - items: - type: integer - type: array - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" - example: "\U0001F93F aqua" - type: string - owner_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\ - \u0435\u043B\u044F, \u0441\u043E\u0437\u0434\u0430\u0432\u0448\u0435\u0433\ - \u043E \u0431\u0435\u0441\u0435\u0434\u0443 \u0438\u043B\u0438 \u043A\u0430\ - \u043D\u0430\u043B" - example: 185 - type: integer - public: - description: "\u0414\u043E\u0441\u0442\u0443\u043F: \u0437\u0430\u043A\u0440\ - \u044B\u0442\u044B\u0439 (false) \u0438\u043B\u0438 \u043E\u0442\u043A\ - \u0440\u044B\u0442\u044B\u0439 (true)" - example: false - type: boolean - type: object - CreateMessage: - properties: - buttons: - $ref: '#/components/schemas/Buttons' - title: buttons - content: - title: Content - type: string - entity_id: - title: Entity Id - type: integer - entity_type: - default: discussion - enum: - - discussion - - user - - thread - title: Entity Type - type: string - files: - items: - properties: - file_type: - enum: - - file - - image - title: File Type - type: string - key: - title: Key - type: string - name: - title: Name - type: string - size: - title: Size - type: integer - required: - - key - - name - - file_type - - size - type: object - title: Files - type: array - link_preview: - default: false - title: Link Preview - type: boolean - parent_message_id: - default: null - nullable: true - title: Parent Massage Id - type: integer - skip_invite_mentions: - default: false - title: Skip Invite Mentions - type: boolean - required: - - entity_id - - content - type: object - DirectResponse: - properties: - Content-Disposition: - type: string - acl: - type: string - file: - type: string - key: - type: string - policy: - type: string - x-amz-algorithm: - type: string - x-amz-credential: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - type: object - EditMessages: - description: "\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\ - \u044F \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0432\u0430\ - \u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0437\ - \u043D\u0430\u0442\u044C \u0435\u0433\u043E id \u0438 \u0443\u043A\u0430\u0437\ - \u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\u0440\u043E\ - \u0441\u0430." - properties: - buttons: - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0441\u0442\u0440\u043E\ - \u043A, \u043A\u0430\u0436\u0434\u0430\u044F \u0438\u0437 \u043A\u043E\ - \u0442\u043E\u0440\u044B\u0445 \u043F\u0440\u0435\u0434\u0441\u0442\u0430\ - \u0432\u043B\u0435\u043D\u0430 \u043C\u0430\u0441\u0441\u0438\u0432\u043E\ - \u043C \u043A\u043D\u043E\u043F\u043E\u043A. \u041F\u043E\u0434\u0440\u043E\ - \u0431\u043D\u0435\u0435 \u043E \u0442\u043E\u043C, \u043A\u0430\u043A\ - \ \u0444\u043E\u0440\u043C\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\ - \u0442\u0440\u043E\u043A\u0438 \u043A\u043D\u043E\u043F\u043E\u043A \u0438\ - \ \u043A\u0430\u043A\u0438\u0435 \u0435\u0441\u0442\u044C \u043E\u0433\ - \u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u044F \u0432\u044B \u043C\ - \u043E\u0436\u0435\u0442\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\ - \u0442\u044C \u0432 \u0441\u0442\u0430\u0442\u044C\u0435. \u0414\u043B\ - \u044F \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u043A\u043D\u043E\ - \u043F\u043E\u043A \u0443 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ - \u044F \u043F\u0440\u0438\u0448\u043B\u0438\u0442\u0435 \u043F\u0443\u0441\ - \u0442\u043E\u0439 \u043C\u0430\u0441\u0441\u0438\u0432." - items: - items: - properties: - data: - description: "\u0414\u0430\u043D\u043D\u044B\u0435, \u043A\u043E\ - \u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442\ - \ \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u044B\ - \ \u0432 \u0438\u0441\u0445\u043E\u0434\u044F\u0449\u0435\u043C\ - \ \u0432\u0435\u0431\u0445\u0443\u043A\u0435 \u043F\u043E \u043D\ - \u0430\u0436\u0430\u0442\u0438\u044E \u043A\u043D\u043E\u043F\u043A\ - \u0438" - type: string - text: - description: "\u0422\u0435\u043A\u0441\u0442, \u043E\u0442\u043E\ - \u0431\u0440\u0430\u0436\u0430\u0435\u043C\u044B\u0439 \u043D\u0430\ - \ \u043A\u043D\u043E\u043F\u043A\u0435 \u043F\u043E\u043B\u044C\ - \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E" - type: string - url: - description: "\u0421\u0441\u044B\u043B\u043A\u0430, \u043A\u043E\ - \u0442\u043E\u0440\u0430\u044F \u0431\u0443\u0434\u0435\u0442\ - \ \u043E\u0442\u043A\u0440\u044B\u0442\u0430 \u043F\u043E \u043D\ - \u0430\u0436\u0430\u0442\u0438\u044E \u043A\u043D\u043E\u043F\u043A\ - \u0438" - type: string - type: object - type: array - type: array - content: - default: "\u0422\u0435\u043A\u0441\u0442 \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u044F" - description: "\u0422\u0435\u043A\u0441\u0442 \u0441\u043E\u043E\u0431\u0449\ - \u0435\u043D\u0438\u044F" - type: string - files: - properties: - file_type: - enum: - - file - - image - type: string - key: - description: "\u041F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\ - \u0443, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043D\u044B\u0439\ - \ \u0432 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0435\ - \ \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0444\u0430\u0439\ - \u043B\u0430 (\u043A\u0430\u0436\u0434\u044B\u0439 \u0444\u0430\u0439\ - \u043B \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0441\u043E\u043E\ - \u0431\u0449\u0435\u043D\u0438\u0438 \u0434\u043E\u043B\u0436\u0435\ - \u043D \u0438\u043C\u0435\u0442\u044C \u0441\u0432\u043E\u0439 \u0443\ - \u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 key, \u043D\ - \u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\ - \u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\ - \u043D\u0438\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u0438 \u0442\ - \u043E\u0433\u043E \u0436\u0435 key \u0432 \u0440\u0430\u0437\u043D\ - \u044B\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - \u0445)" - type: string - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0444\ - \u0430\u0439\u043B\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0435\ - \ \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0442\u043E\ - \u0431\u0440\u0430\u0436\u0430\u0442\u044C \u043F\u043E\u043B\u044C\ - \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E (\u0440\u0435\u043A\ - \u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u043F\ - \u0438\u0441\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\u0435\ - \ \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435\ - \u043C)" - type: string - size: - default: 1234 - description: "\u0420\u0430\u0437\u043C\u0435\u0440 \u0444\u0430\u0439\ - \u043B\u0430 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445, \u043E\u0442\ - \u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u044B\u0439 \u043F\ - \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E" - type: integer - type: object - type: object - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - description: "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u043D\u044B\ - \u0439 \u043A\u043B\u0430\u0441\u0441 \u0441\u043E\u0442\u0440\u0443\u0434\ - \u043D\u0438\u043A\u0430." - properties: - created_at: - description: "\u0414\u0430\u0442\u0430 \u0441\u043E\u0437\u0434\u0430\u043D\ - \u0438\u044F (ISO-8601, UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\ - \u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ\n" - format: date-time - type: string - image_url: - description: "\u0421\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0441\ - \u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0430\u0432\u0430\ - \u0442\u0430\u0440\u043A\u0438" - nullable: true - type: string - time_zone: - description: "\u0427\u0430\u0441\u043E\u0432\u043E\u0439 \u043F\u043E\u044F\ - \u0441 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ - \u044F" - type: string - title: - description: "\u0414\u043E\u043B\u0436\u043D\u043E\u0441\u0442\u044C" - type: string - user_status: - $ref: '#/components/schemas/Status' - type: object - Errors: - items: - properties: - code: - title: code - type: string - key: - title: key - type: string - message: - title: message - type: string - payload: - title: payload - type: object - value: - title: value - type: string - title: Error - type: object - title: Errors - type: array - ErrorsCode: - description: Bad Request - properties: - code: - type: string - key: - type: string - message: - type: string - payload: - type: object - value: - type: string - type: object - FileResponse: - properties: - Content-Disposition: - type: string - acl: - type: string - direct_url: - type: string - key: - type: string - policy: - type: string - x-amz-algorithm: - type: string - x-amz-credential: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - type: object - Message: - properties: - buttons: - $ref: '#/components/schemas/Buttons' - title: buttons - chat_id: - title: Chat Id - type: integer - content: - title: Content - type: string - created_at: - format: date-time - title: Created At - type: string - entity_id: - title: Entity Id - type: integer - entity_type: - default: discussion - enum: - - discussion - - user - - thread - title: Entity Type - type: string - files: - items: - properties: - file_type: - enum: - - file - - image - title: File Type - type: string - id: - title: Id - type: integer - key: - description: "\u041F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\ - \u0443, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043D\u044B\u0439\ - \ \u0432 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0435\ - \ \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0444\u0430\u0439\ - \u043B\u0430 (\u043A\u0430\u0436\u0434\u044B\u0439 \u0444\u0430\u0439\ - \u043B \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0441\u043E\u043E\ - \u0431\u0449\u0435\u043D\u0438\u0438 \u0434\u043E\u043B\u0436\u0435\ - \u043D \u0438\u043C\u0435\u0442\u044C \u0441\u0432\u043E\u0439 \u0443\ - \u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 key, \u043D\ - \u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\ - \u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\ - \u043D\u0438\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u0438 \u0442\ - \u043E\u0433\u043E \u0436\u0435 key \u0432 \u0440\u0430\u0437\u043D\ - \u044B\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - \u0445)" - title: Key - type: string - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0444\ - \u0430\u0439\u043B\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0435\ - \ \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0442\ - \u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C \u043F\u043E\u043B\ - \u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E (\u0440\u0435\ - \u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F\ - \ \u043F\u0438\u0441\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\ - \u0435 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\ - \u0435\u043C)" - title: Name - type: string - url: - description: "\u0420\u0430\u0437\u043C\u0435\u0440 \u0444\u0430\u0439\ - \u043B\u0430 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445, \u043E\ - \u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u044B\u0439\ - \ \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ - \u044E" - title: Url - type: string - type: object - title: Files - type: array - forwarding: - default: null - nullable: true - properties: - author_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430, \u0432 \u043A\u043E\ - \u0442\u043E\u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\u0438\ - \u0442\u0441\u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\ - \u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ - \u0438\u0435" - title: Author Id - type: integer - original_chat_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430, \u0432 \u043A\u043E\ - \u0442\u043E\u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\u0438\ - \u0442\u0441\u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\ - \u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ - \u0438\u0435" - title: Original Chat Id - type: integer - original_created_at: - description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\ - \u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043E\u0440\ - \u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u043E\u0433\u043E\ - \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F (ISO-8601,\ - \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" - title: Original Created At - type: integer - original_message_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u043E\u0440\u0438\u0433\u0438\u043D\u0430\ - \u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\ - \u0435\u043D\u0438\u044F" - title: Origin Message Id - type: integer - original_thread_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u0442\u0440\u0435\u0434\u0430, \u0432 \u043A\ - \u043E\u0442\u043E\u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\ - \u0438\u0442\u0441\u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\ - \u043B\u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u0435. \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\ - \u0435\u0442\u0441\u044F \u043A\u0430\u043A null, \u0435\u0441\u043B\ - \u0438 \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\ - \u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - \ \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A\ - \u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0435\u043C\ - \ \u0432 \u0442\u0440\u0435\u0434\u0435." - nullable: true - title: Original Thread Id - type: integer - original_thread_message_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ - \u0438\u044F, \u043A \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443\ - \ \u0431\u044B\u043B \u0441\u043E\u0437\u0434\u0430\u043D \u0442\u0440\ - \u0435\u0434, \u0432 \u043A\u043E\u0442\u043E\u0440\u043E\u043C \u043D\ - \u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u043E\u0440\u0438\ - \u0433\u0438\u043D\u0430\u043B\u044C\u043D\u043E\u0435 \u0441\u043E\ - \u043E\u0431\u0449\u0435\u043D\u0438\u0435. \u0412\u043E\u0437\u0432\ - \u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A\ - \ null, \u0435\u0441\u043B\u0438 \u043E\u0440\u0438\u0433\u0438\u043D\ - \u0430\u043B\u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\ - \u0435\u043D\u0438\u0435 \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\ - \u0442\u0441\u044F \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\ - \u0440\u0438\u0435\u043C \u0432 \u0442\u0440\u0435\u0434\u0435." - nullable: true - title: Original Thread Message Id - type: integer - original_thread_parent_chat_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430 \u0441\u043E\u043E\ - \u0431\u0449\u0435\u043D\u0438\u044F, \u043A \u043A\u043E\u0442\u043E\ - \u0440\u043E\u043C\u0443 \u0431\u044B\u043B \u0441\u043E\u0437\u0434\ - \u0430\u043D \u0442\u0440\u0435\u0434, \u0432 \u043A\u043E\u0442\u043E\ - \u0440\u043E\u043C \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\ - \u044F \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\ - \u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - . \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\ - \u044F \u043A\u0430\u043A null, \u0435\u0441\u043B\u0438 \u043E\u0440\ - \u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u043E\u0435 \u0441\ - \u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\u0435 \u044F\ - \u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A\u043E\u043C\u043C\ - \u0435\u043D\u0442\u0430\u0440\u0438\u0435\u043C \u0432 \u0442\u0440\ - \u0435\u0434\u0435." - nullable: true - title: Original Thread Parent Chat Id - type: integer - title: Forwarding - type: object - id: - title: Id - type: integer - parent_message_id: - default: null - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - , \u043A \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u043D\u0430\ - \u043F\u0438\u0441\u0430\u043D \u043E\u0442\u0432\u0435\u0442. \u0412\u043E\ - \u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\ - \u043A null, \u0435\u0441\u043B\u0438 \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u0435 \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\ - \u044F \u043E\u0442\u0432\u0435\u0442\u043E\u043C." - nullable: true - title: Parent Massage Id - type: integer - thread: - default: null - nullable: true - properties: - chat_id: - title: Chat Id - type: integer - id: - title: Id - type: integer - title: Thread - type: object - user_id: - title: User Id - type: integer - type: object - NotFound: - description: "\u041E\u0431\u044A\u0435\u043A\u0442 \u043D\u0435 \u043D\u0430\ - \u0439\u0434\u0435\u043D" - properties: - detail: - description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043E\u0448\ - \u0438\u0431\u043A\u0438" - example: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u043D\u0435\ - \ \u043D\u0430\u0439\u0434\u0435\u043D\u0430." - type: string - type: object - QueryChat: - description: "\u0421\u043E\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043E\u0431\ - \u044A\u0435\u043A\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\ - \u0432 \u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0435\u043C\u043E\u0439\ - \ \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\ - \u0430\u043B\u0430" - properties: - channel: - description: "\u0422\u0438\u043F: \u0431\u0435\u0441\u0435\u0434\u0430 (\u043F\ - \u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E, false)\ - \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B (true)" - example: true - type: boolean - member_ids: - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ - \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u043F\ - \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439\ - , \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\u0442\u0430\u043D\u0443\ - \u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u0430\u043C\u0438" - example: - - 186 - - 187 - items: - type: integer - type: array - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" - example: "\U0001F93F aqua" - type: string - public: - description: "\u0414\u043E\u0441\u0442\u0443\u043F: \u0437\u0430\u043A\u0440\ - \u044B\u0442\u044B\u0439 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\ - \u043D\u0438\u044E, false) \u0438\u043B\u0438 \u043E\u0442\u043A\u0440\ - \u044B\u0442\u044B\u0439 (true)" - example: false - type: boolean - required: - - name - type: object - QueryCommonMethods: - description: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0441\u043F\ - \u0438\u0441\u043A\u0430 \u0430\u043A\u0442\u0443\u043B\u044C\u043D\u044B\u0445\ - \ \u043F\u043E\u043B\u0435\u0439 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\ - \u0438." - properties: - data_type: - description: "\u0442\u0438\u043F \u043F\u043E\u043B\u044F (string, number,\ - \ date \u0438\u043B\u0438 link)" - example: number - type: string - id: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\ - \u043B\u044F" - example: 1 - type: integer - name: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u043F\u043E\u043B\u044F" - example: "\u0414\u0430\u0442\u0430 \u0440\u043E\u0436\u0434\u0435\u043D\u0438\ - \u044F" - type: string - type: object - QueryStatus: - properties: - status: - description: "\u0421\u043E\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043E\ - \u0431\u044A\u0435\u043A\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\ - \u0440\u043E\u0432 \u043D\u043E\u0432\u043E\u0433\u043E \u0441\u0442\u0430\ - \u0442\u0443\u0441\u0430" - properties: - emoji: - description: "Emoji \u0441\u0438\u043C\u0432\u043E\u043B \u0441\u0442\ - \u0430\u0442\u0443\u0441\u0430" - type: string - expires_at: - description: "\u0421\u0440\u043E\u043A \u0434\u0435\u0439\u0441\u0442\ - \u0432\u0438\u044F \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (ISO-8601,\ - \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ" - format: date-time - nullable: true - type: string - title: - description: "\u0422\u0435\u043A\u0441\u0442 \u0441\u0442\u0430\u0442\ - \u0443\u0441\u0430" - type: string - required: - - emoji - - title - type: object - type: object - Reaction: - properties: - code: - description: "Emoji \u0441\u0438\u043C\u0432\u043E\u043B \u0440\u0435\u0430\ - \u043A\u0446\u0438\u0438.\n" - type: string - created_at: - description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F\ - \ \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0440\u0435\ - \u0430\u043A\u0446\u0438\u0438 (ISO-8601, UTC+0) \u0432 \u0444\u043E\u0440\ - \u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ.\n" - format: date-time - type: string - user_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\ - \u0435\u043B\u044F, \u043E\u0441\u0442\u0430\u0432\u0438\u0432\u0448\u0435\ - \u0433\u043E \u0440\u0435\u0430\u043A\u0446\u0438\u044E.\n" - type: integer - type: object - Status: - description: "\u0421\u0442\u0430\u0442\u0443\u0441. \u0412\u043E\u0437\u0432\ - \u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A null,\ - \ \u0435\u0441\u043B\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u043D\u0435\ - \ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D." - nullable: true - properties: - emoji: - description: "Emoji \u0441\u0438\u043C\u0432\u043E\u043B \u0441\u0442\u0430\ - \u0442\u0443\u0441\u0430" - type: string - expires_at: - description: "\u0421\u0440\u043E\u043A \u0436\u0438\u0437\u043D\u0438 \u0441\ - \u0442\u0430\u0442\u0443\u0441\u0430 (ISO-8601, UTC+0) \u0432 \u0444\u043E\ - \u0440\u043C\u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ. \u0412\u043E\u0437\ - \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A\ - \ null, \u0435\u0441\u043B\u0438 \u0441\u0440\u043E\u043A \u043D\u0435\ - \ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D.\n" - format: date-time - nullable: true - type: string - title: - description: "\u0422\u0435\u043A\u0441\u0442 \u0441\u0442\u0430\u0442\u0443\ - \u0441\u0430" - type: string - type: object - Tag: - description: "\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\ - \u044F \u0442\u0435\u0433\u0430 \u0432\u0430\u043C \u043D\u0435\u043E\u0431\ - \u0445\u043E\u0434\u0438\u043C\u043E \u0437\u043D\u0430\u0442\u044C \u0435\ - \u0433\u043E id \u0438 \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0433\ - \u043E \u0432 URL \u0437\u0430\u043F\u0440\u043E\u0441\u0430." - properties: - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0442\u0435\u0433\u0430" - type: integer - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0442\u0435\ - \u0433\u0430" - type: string - users_count: - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432,\ - \ \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0438\u043C\u0435\u044E\u0442\ - \ \u044D\u0442\u043E\u0442 \u0442\u0435\u0433" - type: integer - type: object - securitySchemes: - bearerAuth: - scheme: bearer - type: http -info: - description: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\ - \u044F \u043A \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u043C\u0443 API \u043F\ - \u0430\u0447\u043A\u0438" - title: PachcaAPI - OpenAPI 3.0 - version: 3.0.3 -openapi: 3.0.3 -paths: - /chats: - get: - description: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u043F\ - \u0438\u0441\u043A\u0430 \u0431\u0435\u0441\u0435\u0434 \u0438 \u043A\u0430\ - \u043D\u0430\u043B\u043E\u0432 \u043F\u043E \u0437\u0430\u0434\u0430\u043D\ - \u043D\u044B\u043C \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\ - ." - operationId: getChats - parameters: - - description: "\u0421\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u043F\ - \u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0441\u043E\u0440\u0442\u0438\ - \u0440\u043E\u0432\u043A\u0438 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\ - \u0435\u0439 \u0432\u044B\u0431\u043E\u0440\u043A\u0438.\n\u0412\u0430\u0440\ - \u0438\u0430\u043D\u0442\u044B \u0437\u043D\u0430\u0447\u0435\u043D\u0438\ - \u0439: \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E\ - \ desc (\u043F\u043E \u0443\u0431\u044B\u0432\u0430\u043D\u0438\u044E) \u0438\ - \u043B\u0438 asc (\u043F\u043E \u0432\u043E\u0437\u0440\u0430\u0441\u0442\ - \u0430\u043D\u0438\u044E).\n\u041D\u0430 \u0434\u0430\u043D\u043D\u044B\u0439\ - \ \u043C\u043E\u043C\u0435\u043D\u0442 \u0441\u043E\u0440\u0442\u0438\u0440\ - \u043E\u0432\u043A\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430\ - \ \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E \u043F\u043E\u043B\u044E\ - \ ({field}) id (\u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434 \u0438 \u043A\u0430\u043D\ - \u0430\u043B\u043E\u0432).\n" - in: query - name: sort[id] - required: false - schema: - default: desc - enum: - - desc - - asc - type: string - - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ - \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ - \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ - \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 25, \u043C\u0430\u043A\u0441\ - \u0438\u043C\u0443\u043C 50)" - in: query - name: per - required: false - schema: - default: 25 - maximum: 50 - type: integer - - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ - \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ - \u0430\u043D\u0438\u044E 1)" - in: query - name: page - required: false - schema: - default: 1 - type: integer - - description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440, \u043A\u043E\ - \u0442\u043E\u0440\u044B\u0439 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\ - \u0442 \u0437\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\ - \u0442\u044C \u0438 \u0432\u044B\u0431\u043E\u0440\u043A\u0443 \u0431\u0435\ - \u0441\u0435\u0434 \u0438 \u043A\u0430\u043D\u0430\u043B\u043E\u0432 \u0434\ - \u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\ - \u043B\u044F.\n\u0412\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u0437\u043D\ - \u0430\u0447\u0435\u043D\u0438\u0439: \u043F\u043E \u0443\u043C\u043E\u043B\ - \u0447\u0430\u043D\u0438\u044E is_member (\u0431\u0435\u0441\u0435\u0434\ - \u044B \u0438 \u043A\u0430\u043D\u0430\u043B\u044B, \u0433\u0434\u0435 \u043F\ - \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u044F\ - \u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0443\u0447\u0430\u0441\u0442\ - \u043D\u0438\u043A\u043E\u043C)\n\u0438\u043B\u0438 public (\u0432\u0441\ - \u0435 \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 \u0431\u0435\u0441\ - \u0435\u0434\u044B \u0438 \u043A\u0430\u043D\u0430\u043B\u044B \u043A\u043E\ - \u043C\u043F\u0430\u043D\u0438\u0438, \u0432\u043D\u0435 \u0437\u0430\u0432\ - \u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438 \u043E\u0442 \u0443\u0447\ - \u0430\u0441\u0442\u0438\u044F \u0432 \u043D\u0438\u0445 \u043F\u043E\u043B\ - \u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F).\n" - in: query - name: availability - required: false - schema: - default: is_member - enum: - - is_member - - public - type: string - - description: "\u0424\u0438\u043B\u044C\u0442\u0440\u0430\u0446\u0438\u044F\ - \ \u043F\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0441\u043E\u0437\ - \u0434\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\ - \u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - .\n\u0411\u0443\u0434\u0443\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\ - \u0435\u043D\u044B \u0442\u0435 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\ - \u0430\u043D\u0430\u043B\u044B, \u0432\u0440\u0435\u043C\u044F \u043F\u043E\ - \u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u0437\u0434\ - \u0430\u043D\u043D\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u044F \u0432 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u043D\ - \u0435 \u0440\u0430\u043D\u044C\u0448\u0435 \u0447\u0435\u043C \u0443\u043A\ - \u0430\u0437\u0430\u043D\u043D\u043E\u0435 (\u0432 \u0444\u043E\u0440\u043C\ - \u0430\u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ).\n" - in: query - name: last_message_at_after - required: false - schema: - format: date-time - type: string - - description: "\u0424\u0438\u043B\u044C\u0442\u0440\u0430\u0446\u0438\u044F\ - \ \u043F\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0441\u043E\u0437\ - \u0434\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\ - \u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - .\n\u0411\u0443\u0434\u0443\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\ - \u0435\u043D\u044B \u0442\u0435 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\ - \u0430\u043D\u0430\u043B\u044B, \u0432\u0440\u0435\u043C\u044F \u043F\u043E\ - \u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u0437\u0434\ - \u0430\u043D\u043D\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u044F \u0432 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u043D\ - \u0435 \u043F\u043E\u0437\u0436\u0435 \u0447\u0435\u043C \u0443\u043A\u0430\ - \u0437\u0430\u043D\u043D\u043E\u0435 (\u0432 \u0444\u043E\u0440\u043C\u0430\ - \u0442\u0435 YYYY-MM-DDThh:mm:ss.sssZ).\n" - in: query - name: last_message_at_before - required: false - schema: - format: date-time - type: string - responses: - '200': - content: - application/json: - schema: - properties: - data: - items: - $ref: '#/components/schemas/Chat' - type: array - type: object - description: "\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0442\u0440\u0430\ - \u0431\u043E\u0442\u0430\u043B \u043A\u0430\u043A \u043F\u043E\u043B\u043E\ - \u0436\u0435\u043D\u043E, \u0431\u0435\u0437 \u043E\u0448\u0438\u0431\u043E\ - \u043A" - '400': - content: - application/json: - examples: - invalid: - description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u0441\u043E\ - \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ - \ \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C (\u043F\u043E\ - \u044F\u0441\u043D\u0435\u043D\u0438\u044F \u0432\u044B \u043F\ - \u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u0432 \u043F\u043E\ - \u043B\u0435 message)" - value: - errors: - - code: invalid - key: name - message: message - payload: {} - value: 1234 - too_long: - description: "\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\ - \u0438\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\ - \u0438\u0435 (\u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\ - \u044F \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\ - \u0435 \u0432 \u043F\u043E\u043B\u0435 message)" - value: - errors: - - code: too_long - key: name - message: message - payload: {} - value: long_name - schema: - properties: - errors: - $ref: '#/components/schemas/ErrorsCode' - type: object - description: "\u041D\u0435\u043F\u0440\u0438\u0435\u043C\u043B\u0435\u043C\ - \u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 (\u0447\u0430\u0441\u0442\ - \u043E \u0438\u0437-\u0437\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\ - \u0432\u0438\u044F \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ - \u043D\u043E\u0433\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\ - \u0430)" - '404': - content: - application/json: - examples: - not_found: - description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438" - value: - errors: - - code: not_found - key: string - message: message - payload: {} - value: string - schema: - properties: - errors: - $ref: '#/components/schemas/Errors' - type: object - description: "\u0417\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\ - \u043C\u044B\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043D\u0435 \u0441\ - \u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442" - '422': - content: - application/json: - examples: - invalid: - description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\ - \u0440\u043C\u0430\u0442 (\u0438\u0434\u0435\u043D\u0442\u0438\ - \u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044F\ - \ \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0435\ - \ \u0432 \u043F\u043E\u043B\u0435 payload)" - value: - errors: - - code: invalid - key: name - message: message - payload: {} - value: name - schema: - properties: - errors: - $ref: '#/components/schemas/Errors' - type: object - description: "\u0421 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u043C \u0432\ - \u0441\u0435 \u0445\u043E\u0440\u043E\u0448\u043E, \u043D\u043E \u043F\ - \u0440\u0430\u0432\u0438\u043B\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\ - \u0430 \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0442\ - \ \u0435\u0433\u043E \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u0442\ - \u044C (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043F\u0440\ - \u0438 \u043F\u043E\u043F\u044B\u0442\u043A\u0435 \u0441\u043E\u0437\u0434\ - \u0430\u043D\u0438\u044F \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0430\ - \ \u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\ - \u0443\u044E\u0449\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C\ - \ \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0432 \u0431\u0430\ - \u0437\u0435)" - summary: "\u0421\u043F\u0438\u0441\u043E\u043A \u0431\u0435\u0441\u0435\u0434\ - \ \u0438 \u043A\u0430\u043D\u0430\u043B\u043E\u0432" - tags: - - chats and channels - post: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0441\u043E\ - \u0437\u0434\u0430\u043D\u0438\u044F \u043D\u043E\u0432\u043E\u0439 \u0431\ - \u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043D\u043E\u0432\u043E\ - \u0433\u043E \u043A\u0430\u043D\u0430\u043B\u0430.\n\u041F\u0440\u0438 \u0441\ - \u043E\u0437\u0434\u0430\u043D\u0438\u0438 \u0431\u0435\u0441\u0435\u0434\u044B\ - \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430 \u0432\u044B \u0430\ - \u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0441\ - \u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435\u0441\u044C \u0443\u0447\u0430\ - \u0441\u0442\u043D\u0438\u043A\u043E\u043C.\\\n" - operationId: createChat - requestBody: - content: - application/json: - schema: - properties: - chat: - $ref: '#/components/schemas/QueryChat' - type: object - required: true - responses: - '201': - content: - application/json: - schema: - properties: - data: - $ref: '#/components/schemas/Chat' - type: object - description: "\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0442\u0440\u0430\ - \u0431\u043E\u0442\u0430\u043B \u0443\u0441\u043F\u0435\u0448\u043D\u043E\ - , \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u044C \u0441\u043E\u0437\u0434\ - \u0430\u043D\u0430" - '400': - content: - application/json: - examples: - blank: - description: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ - \u043D\u043E\u0435 \u043F\u043E\u043B\u0435 (\u043D\u0435 \u043C\ - \u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\ - \u0441\u0442\u044B\u043C)" - value: - errors: - - code: blank - key: name - message: message - payload: {} - value: '' - invalid: - description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u0441\u043E\ - \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ - \ \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C (\u043F\u043E\ - \u044F\u0441\u043D\u0435\u043D\u0438\u044F \u0432\u044B \u043F\ - \u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u0432 \u043F\u043E\ - \u043B\u0435 message)" - value: - errors: - - code: invalid - key: name - message: message - payload: {} - value: 1234 - too_long: - description: "\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\ - \u0438\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\ - \u0438\u0435 (\u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\ - \u044F \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\ - \u0435 \u0432 \u043F\u043E\u043B\u0435 message)" - value: - errors: - - code: too_long - key: name - message: message - payload: {} - value: long_name - schema: - properties: - errors: - $ref: '#/components/schemas/Errors' - type: object - description: "\u041D\u0435\u043F\u0440\u0438\u0435\u043C\u043B\u0435\u043C\ - \u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 (\u0447\u0430\u0441\u0442\ - \u043E \u0438\u0437-\u0437\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\ - \u0432\u0438\u044F \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ - \u043D\u043E\u0433\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\ - \u0430)" - '404': - content: - application/json: - examples: - not_found: - description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438" - value: - errors: - - code: not_found - key: string - message: message - payload: {} - value: string - schema: - properties: - errors: - $ref: '#/components/schemas/Errors' - type: object - description: "\u0417\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\ - \u043C\u044B\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043D\u0435 \u0441\ - \u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442" - '422': - content: - application/json: - examples: - invalid: - description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\ - \u0440\u043C\u0430\u0442 (\u0438\u0434\u0435\u043D\u0442\u0438\ - \u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044F\ - \ \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0435\ - \ \u0432 \u043F\u043E\u043B\u0435 payload)" - value: - errors: - - code: invalid - key: name - message: message - payload: {} - value: name - schema: - properties: - errors: - $ref: '#/components/schemas/Errors' - type: object - description: "\u0421 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u043C \u0432\ - \u0441\u0435 \u0445\u043E\u0440\u043E\u0448\u043E, \u043D\u043E \u043F\ - \u0440\u0430\u0432\u0438\u043B\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\ - \u0430 \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0442\ - \ \u0435\u0433\u043E \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u0442\ - \u044C (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043F\u0440\ - \u0438 \u043F\u043E\u043F\u044B\u0442\u043A\u0435 \u0441\u043E\u0437\u0434\ - \u0430\u043D\u0438\u044F \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0430\ - \ \u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\ - \u0443\u044E\u0449\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C\ - \ \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0432 \u0431\u0430\ - \u0437\u0435)" - summary: "\u041D\u043E\u0432\u0430\u044F \u0431\u0435\u0441\u0435\u0434\u0430\ - \ \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B" - tags: - - chats and channels - /chats/{id}: - get: - description: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0438\u043D\ - \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0431\u0435\u0441\ - \u0435\u0434\u0435 \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0435\ - .\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F\ - \ \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\ - \u0430\u043B\u0430 \u0432\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\ - \u0434\u0438\u043C\u043E \u0437\u043D\u0430\u0442\u044C \u0435\u0451 id \u0438\ - \ \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL\ - \ \u0437\u0430\u043F\u0440\u043E\u0441\u0430.\n" - operationId: getChat - parameters: - - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438\ - \ \u043A\u0430\u043D\u0430\u043B\u0430" - in: path - name: id - required: true - schema: - type: integer - responses: - '200': - content: - application/json: - schema: - properties: - data: - $ref: '#/components/schemas/Chat' - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - '404': - content: - application/json: - examples: - not_found: - description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438" - value: - errors: - - code: not_found - key: string - message: message - payload: {} - value: string - schema: - properties: - errors: - $ref: '#/components/schemas/Errors' - type: object - description: "\u0417\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\ - \u043C\u044B\u0439 \u0440\u0435\u0441\u0443\u0440\u0441 \u043D\u0435 \u0441\ - \u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442" - summary: "\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ - \ \u0431\u0435\u0441\u0435\u0434\u0435 \u0438\u043B\u0438 \u043A\u0430\u043D\ - \u0430\u043B\u0435" - tags: - - chats and channels - /chats/{id}/group_tags: - post: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0434\u043E\ - \u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0442\u0435\u0433\u043E\u0432\ - \ \u0432 \u0441\u043E\u0441\u0442\u0430\u0432 \u0443\u0447\u0430\u0441\u0442\ - \u043D\u0438\u043A\u043E\u0432 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\ - \u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430.\n" - operationId: postTagsToChats - parameters: - - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\u0430\u043D\ - \u0430\u043B\u0430" - in: path - name: id - required: true - schema: - example: 533 - format: int64 - type: integer - requestBody: - content: - application/json: - schema: - properties: - group_tag_ids: - example: - - 86 - - 18 - items: - format: int64 - type: integer - minItems: 1 - type: array - required: - - group_tag_ids - type: object - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ - \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u0442\ - \u0435\u0433\u043E\u0432, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\ - \u0442\u0430\u043D\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\ - \u043A\u0430\u043C\u0438" - responses: - '201': - description: "\u0422\u0435\u0433(\u0438) \u0434\u043E\u0431\u0430\u0432\u043B\ - \u0435\u043D(\u044B)" - '400': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ErrorsCode' - type: array - description: BadRequest - summary: "\u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0442\ - \u0435\u0433\u043E\u0432 \u0432 \u0441\u043E\u0441\u0442\u0430\u0432 \u0443\ - \u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u0432 \u0431\u0435\u0441\u0435\ - \u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430" - tags: - - talk and channel participants - /chats/{id}/leave: - delete: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0441\u0430\ - \u043C\u043E\u0441\u0442\u043E\u044F\u0442\u0435\u043B\u044C\u043D\u043E\u0433\ - \u043E \u0432\u044B\u0445\u043E\u0434\u0430 \u0438\u0437 \u0431\u0435\u0441\ - \u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430\ - ." - operationId: leaveChat - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\ - \u043D\u0430\u043B\u0430." - in: path - name: id - required: true - schema: - type: integer - responses: - '200': - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0442\u043F\ - \u0438\u0441\u0430\u043D. \u0422\u0435\u043B\u043E \u043E\u0442\u0432\u0435\ - \u0442\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\ - \u0442" - '400': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ErrorsCode' - type: array - description: "\u041D\u0435\u043B\u044C\u0437\u044F \u043F\u043E\u043A\u0438\ - \u043D\u0443\u0442\u044C \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\ - \u044C\u043D\u044B\u0439 \u0447\u0430\u0442" - '404': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ErrorsCode' - type: array - description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043D\ - \u0430\u0439\u0442\u0438" - summary: "\u0412\u044B\u0445\u043E\u0434 \u0438\u0437 \u0431\u0435\u0441\u0435\ - \u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\u0430\u043B\u0430" - tags: - - talk and channel participants - /chats/{id}/members: - post: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0434\u043E\ - \u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\ - \u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u0441\u043E\u0441\ - \u0442\u0430\u0432 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u0432\ - \ \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\u043D\ - \u0430\u043B\u0430.\n" - operationId: postMembersToChats - parameters: - - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0431\u0435\u0441\u0435\u0434\u044B/\u043A\u0430\u043D\ - \u0430\u043B\u0430" - in: path - name: id - required: true - schema: - example: 533 - format: int64 - type: integer - requestBody: - content: - application/json: - schema: - properties: - member_ids: - example: - - 186 - - 187 - items: - format: int64 - type: integer - minItems: 1 - type: array - silent: - type: boolean - required: - - member_ids - type: object - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ - \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u043F\ - \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439\ - , \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\u0442\u0430\u043D\u0443\ - \u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u0430\u043C\u0438" - responses: - '201': - description: "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\ - \u043B\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B" - '400': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ErrorsCode' - type: array - description: BadRequest - summary: "\u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\ - \u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432\ - \ \u0441\u043E\u0441\u0442\u0430\u0432 \u0443\u0447\u0430\u0441\u0442\u043D\ - \u0438\u043A\u043E\u0432" - tags: - - talk and channel participants - /custom_properties: - get: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u043A\u0442\u0443\u0430\u043B\ - \u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0430 \u0434\ - \u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445\ - \ \u043F\u043E\u043B\u0435\u0439 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\ - \u043A\u043E\u0432 \u0438 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\ - \u043D\u0438\u0439 \u0432 \u0432\u0430\u0448\u0435\u0439 \u043A\u043E\u043C\ - \u043F\u0430\u043D\u0438\u0438.\n" - operationId: getCommonMethods - parameters: - - description: "\u0422\u0438\u043F \u0441\u0443\u0449\u043D\u043E\u0441\u0442\ - \u0438 - \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A (User) \u0438\u043B\ - \u0438 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u0435\ - \ (Task)." - in: query - name: entity_type - required: true - schema: - type: string - responses: - '200': - content: - application/json: - schema: - properties: - data: - items: - $ref: '#/components/schemas/QueryCommonMethods' - type: array - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - '400': - content: - application/json: - examples: - BLANK: - description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ - \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ - \u0442\u044B\u043C" - summary: blank - value: - detail: BLANK - INCLUSION: - description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u043F\u0440\u0435\u0434\u0443\u0441\u043C\u043E\ - \u0442\u0440\u0435\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\ - \u0435\u043D\u0438\u0435" - summary: inclusion - value: - detail: INCLUSION - schema: - $ref: '#/components/schemas/BadRequest' - description: BadRequest - summary: "\u0421\u043F\u0438\u0441\u043E\u043A \u0434\u043E\u043F\u043E\u043B\ - \u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u043F\u043E\u043B\u0435\ - \u0439" - tags: - - common methods - /direct_url: - post: - description: "\u041E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u0442 \u0437\ - \u0430\u043F\u0440\u043E\u0441 \u0434\u043B\u044F \u043F\u043E\u043B\u0443\ - \u0447\u0435\u043D\u0438\u044F URL \u0434\u043B\u044F \u0431\u0435\u0437\u043E\ - \u043F\u0430\u0441\u043D\u043E\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\ - \u0438 \u0444\u0430\u0439\u043B\u0430." - operationId: getDirectUrl - requestBody: - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - required: true - responses: - '204': - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441." - summary: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 URL \u0434\u043B\ - \u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438" - tags: - - common methods - /group_tags: - get: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u043A\u0442\u0443\u0430\u043B\ - \u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0430 \u0442\ - \u0435\u0433\u043E\u0432 \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\ - \u043E\u0432.\n" - operationId: getTags - parameters: - - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ - \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ - \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ - \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\ - \u0438\u043C\u0443\u043C 50)" - in: query - name: per - required: false - schema: - default: 50 - maximum: 50 - type: integer - - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ - \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ - \u0430\u043D\u0438\u044E 1)" - in: query - name: page - required: false - schema: - default: 1 - type: integer - responses: - '200': - content: - application/json: - schema: - properties: - data: - items: - $ref: '#/components/schemas/Tag' - type: array - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - '400': - content: - application/json: - examples: - exclusion: - summary: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\ - \u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\ - \ \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\ - \u044B\u0445 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439\ - \ \u0437\u0430 \u043E\u0434\u0438\u043D \u0437\u0430\u043F\u0440\ - \u043E\u0441" - value: - errors: - - code: exclusion - key: per - message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ - \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" - value: '51' - schema: - properties: - errors: - description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ - \u0438\u0431\u043E\u043A \u0432 \u0437\u0430\u043F\u0440\u043E\ - \u0441\u0435." - items: - properties: - code: - description: "\u0412\u043D\u0443\u0442\u0440\u0435\u043D\ - \u043D\u0438\u0439 \u043A\u043E\u0434 \u043E\u0448\u0438\ - \u0431\u043A\u0438." - type: string - key: - description: "\u041A\u043B\u044E\u0447 \u043F\u0430\u0440\ - \u0430\u043C\u0435\u0442\u0440\u0430, \u0432 \u043A\u043E\ - \u0442\u043E\u0440\u043E\u043C \u043F\u0440\u043E\u0438\ - \u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\ - \u043A\u0430." - type: string - message: - description: "\u0422\u0435\u043A\u0441\u0442\u043E\u0432\ - \u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\ - \u0435 \u043E\u0448\u0438\u0431\u043A\u0438." - type: string - payload: - description: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\ - \u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0438\u043D\ - \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ - \u0431 \u043E\u0448\u0438\u0431\u043A\u0435." - type: object - value: - description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ - \u0435 \u043A\u043B\u044E\u0447\u0430, \u0432\u044B\u0437\ - \u0432\u0430\u0432\u0448\u0435\u0435 \u043E\u0448\u0438\ - \u0431\u043A\u0443." - type: string - type: object - type: array - type: object - description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\ - \u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\ - ." - summary: "\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u0435\u0433\u043E\u0432\ - \ \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432" - tags: - - tags - /group_tags/{id}: - get: - description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\ - \u043F\u0440\u043E\u0441\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\ - \u0443\u044E\u0442\n" - operationId: getTag - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0442\u0435\u0433\u0430" - in: path - name: id - required: true - schema: - type: integer - responses: - '200': - content: - application/json: - schema: - properties: - data: - $ref: '#/components/schemas/Tag' - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - '404': - content: - application/json: - examples: - not_found: - summary: "\u0422\u0435\u0433 \u043D\u0435 \u043D\u0430\u0439\u0434\ - \u0435\u043D." - value: - errors: - - code: not_found - key: id - message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438 \u0442\u0435\u0433" - value: '100500' - schema: - properties: - errors: - description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ - \u0438\u0431\u043E\u043A." - items: - properties: - code: - type: string - key: - type: string - message: - type: string - payload: - type: object - value: - type: string - type: object - type: array - type: object - description: "\u0422\u0435\u0433 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\ - \u043D." - summary: "\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ - \ \u0442\u0435\u0433\u0435" - tags: - - tags - /group_tags/{id}/users: - get: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0430\u043A\u0442\u0443\u0430\u043B\ - \u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\u043A\u0430 \u0441\ - \u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432 \u0442\u0435\u0433\ - \u0430.\n" - operationId: getTagsEmployees - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0441\u043E\u0442\u0440\u0443\u0434\u043A\u0438\u043A\u0430" - in: path - name: id - required: true - schema: - type: integer - - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ - \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ - \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ - \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\ - \u0438\u043C\u0443\u043C" - in: query - name: per - required: false - schema: - default: 25 - maximum: 50 - type: integer - - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ - \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ - \u0430\u043D\u0438\u044E 1)" - in: query - name: page - required: false - schema: - default: 1 - type: integer - responses: - '200': - content: - application/json: - schema: - properties: - data: - items: - $ref: '#/components/schemas/BaseEmployee' - type: array - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/BadRequest' - description: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442 \u043D\ - \u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0437\ - \u043D\u0430\u0447\u0435\u043D\u0438\u0435" - summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0430\u043A\ - \u0442\u0443\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\ - \u043A\u0430 \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u043E\u0432\ - \ \u0442\u0435\u0433\u0430" - tags: - - tags - /messages: - get: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u043F\u0438\u0441\u043A\u0430\ - \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439 \u0431\u0435\u0441\ - \u0435\u0434, \u043A\u0430\u043D\u0430\u043B\u043E\u0432, \u0442\u0440\u0435\ - \u0434\u043E\u0432 \u0438 \u043B\u0438\u0447\u043D\u044B\u0445 \u0441\u043E\ - \u043E\u0431\u0449\u0435\u043D\u0438\u0439.\n\n\u0414\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u0439 \u0432\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\ - \u0434\u0438\u043C\u043E \u0437\u043D\u0430\u0442\u044C chat_id \u0442\u0440\ - \u0435\u0431\u0443\u0435\u043C\u043E\u0439 \u0431\u0435\u0441\u0435\u0434\u044B\ - , \u043A\u0430\u043D\u0430\u043B\u0430,\n\u0442\u0440\u0435\u0434\u0430 \u0438\ - \u043B\u0438 \u0434\u0438\u0430\u043B\u043E\u0433\u0430, \u0438 \u0443\u043A\ - \u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\ - \u0440\u043E\u0441\u0430. \u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ - \u044F \u0431\u0443\u0434\u0443\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\ - \u0449\u0435\u043D\u044B\n\u0432 \u043F\u043E\u0440\u044F\u0434\u043A\u0435\ - \ \u0443\u0431\u044B\u0432\u0430\u043D\u0438\u044F \u0434\u0430\u0442\u044B\ - \ \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 (\u0442\u043E \u0435\u0441\ - \u0442\u044C, \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0431\u0443\u0434\ - \u0443\u0442 \u0438\u0434\u0442\u0438 \u043F\u043E\u0441\u043B\u0435\u0434\ - \u043D\u0438\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - \ \u0447\u0430\u0442\u0430).\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\ - \u0435\u043D\u0438\u044F \u0431\u043E\u043B\u0435\u0435 \u0440\u0430\u043D\ - \u043D\u0438\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439\ - \ \u0447\u0430\u0442\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\ - \ \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B per \u0438 page.\n" - operationId: getListMessage - parameters: - - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\ - \u0442\u043E\u0440 \u0447\u0430\u0442\u0430 (\u0431\u0435\u0441\u0435\u0434\ - \u0430, \u043A\u0430\u043D\u0430\u043B, \u0434\u0438\u0430\u043B\u043E\u0433\ - \ \u0438\u043B\u0438 \u0447\u0430\u0442 \u0442\u0440\u0435\u0434\u0430)" - in: query - name: chat_id - required: true - schema: - title: chat_id - type: integer - - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ - \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ - \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441\n(\u043F\u043E \u0443\ - \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 25, \u043C\u0430\u043A\u0441\ - \u0438\u043C\u0443\u043C 50)\n" - in: query - name: per - schema: - default: 25 - maximum: 50 - title: per - type: integer - - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ - \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ - \u0430\u043D\u0438\u044E 1)" - in: query - name: page - schema: - default: 1 - title: page - type: integer - responses: - '200': - content: - application/json: - example: - data: - - buttons: [] - chat_id: 198 - content: "\u042D\u0442\u043E \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u0435 \u0442\u043E\u0436\u0435 \u043F\u043E\u043F\ - \u0430\u0434\u0451\u0442 \u0432 \u044D\u043A\u0441\u043F\u043E\ - \u0440\u0442" - created_at: 2023-09-18 13:43:32+00:00 - entity_id: 198 - entity_type: discussion - files: [] - forwarding: null - id: 1194277 - parent_message_id: null - thread: - chat_id: 44997 - id: 2633 - user_id: 12 - - buttons: [] - chat_id: 198 - content: "**Andrew** \u0434\u043E\u0431\u0430\u0432\u0438\u043B\ - \ **Export bot** \u0432 \u0431\u0435\u0441\u0435\u0434\u0443" - created_at: 2023-09-18 13:43:27+00:00 - entity_id: 198 - entity_type: discussion - files: [] - forwarding: null - id: 1194276 - parent_message_id: null - thread: null - user_id: 12 - - buttons: [] - chat_id: 198 - content: "**Andrew** \u0441\u043E\u0437\u0434\u0430\u043B \u0431\ - \u0435\u0441\u0435\u0434\u0443" - created_at: 2023-09-18 13:43:19+00:00 - entity_id: 198 - entity_type: discussion - files: [] - forwarding: null - id: 1194275 - parent_message_id: null - thread: null - user_id: 12 - schema: - properties: - data: - items: - $ref: '#/components/schemas/Message' - type: array - type: object - description: Successful - '400': - content: - application/json: - examples: - INVALID FIELD VALUE: - summary: invalid field value - value: - errors: - - code: exclusion - key: chat_id - message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ - \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" - value: chat - REQUIRED FIELD BLANK: - summary: required fields blank - value: - errors: - - code: blank - key: chat_id - message: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ - \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ - \u0442\u044B\u043C" - value: null - schema: - $ref: '#/components/schemas/BadRequest' - description: Bad Request - '404': - content: - application/json: - example: - errors: - - code: not_found - key: chat_id - message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438" - value: 1 - schema: - $ref: '#/components/schemas/NotFound' - description: Not Found - summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0441\u043F\ - \u0438\u0441\u043A\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439\ - \ \u0447\u0430\u0442\u0430" - tags: - - messages - post: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043E\u0442\ - \u043F\u0440\u0430\u0432\u043A\u0438 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ - \u0438\u044F \u0432 \u0431\u0435\u0441\u0435\u0434\u0443 \u0438\u043B\u0438\ - \ \u043A\u0430\u043D\u0430\u043B,\n\u043B\u0438\u0447\u043D\u043E\u0433\u043E\ - \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u043E\u043B\ - \u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0438\u043B\u0438\ - \ \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F \u0432\ - \ \u0442\u0440\u0435\u0434.\n\n\u041F\u0440\u0438 \u0438\u0441\u043F\u043E\ - \u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0438 entity_type: \"discussion\"\ - \ (\u0438\u043B\u0438 \u043F\u0440\u043E\u0441\u0442\u043E \u0431\u0435\u0437\ - \ \u0443\u043A\u0430\u0437\u0430\u043D\u0438\u044F entity_type)\n\u0434\u043E\ - \u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\u044F \u043E\u0442\u043F\u0440\ - \u0430\u0432\u043A\u0430 \u043B\u044E\u0431\u043E\u0433\u043E chat_id \u0432\ - \ \u043F\u043E\u043B\u0435 entity_id.\n\u0422\u043E \u0435\u0441\u0442\u044C\ - , \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\ - \u043D\u043E \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0437\ - \u043D\u0430\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0434\u0435\ - \u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0447\u0430\u0442\ - \u0430.\n\u041F\u0440\u0438 \u044D\u0442\u043E\u043C, \u0432\u044B \u0438\u043C\ - \u0435\u0435\u0442\u0435 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\ - \u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0441\ - \u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0432 \u0442\u0440\u0435\ - \u0434 \u043F\u043E \u0435\u0433\u043E \u0438\u0434\u0435\u043D\u0442\u0438\ - \u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443\n\u0438\u043B\u0438 \u043B\ - \u0438\u0447\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ - \u0435 \u043F\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\ - \u0430\u0442\u043E\u0440\u0443 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\ - \u0442\u0435\u043B\u044F.\n\n\u0414\u043B\u044F \u043E\u0442\u043F\u0440\u0430\ - \u0432\u043A\u0438 \u043B\u0438\u0447\u043D\u043E\u0433\u043E \u0441\u043E\ - \u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\ - \u0432\u0430\u0442\u0435\u043B\u044E \u0441\u043E\u0437\u0434\u0430\u0432\u0430\ - \u0442\u044C \u0447\u0430\u0442 \u043D\u0435 \u0442\u0440\u0435\u0431\u0443\ - \u0435\u0442\u0441\u044F. \n\u0414\u043E\u0441\u0442\u0430\u0442\u043E\u0447\ - \u043D\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C entity_type: \"user\"\ - \ \u0438 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\ - \u043E\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\ - \u044F. \n\u0427\u0430\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043E\u0437\ - \u0434\u0430\u043D \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\ - \u0441\u043A\u0438, \u0435\u0441\u043B\u0438 \u043C\u0435\u0436\u0434\u0443\ - \ \u0432\u0430\u043C\u0438 \u0435\u0449\u0451 \u043D\u0435 \u0431\u044B\u043B\ - \u043E \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438.\n\u041C\u0435\ - \u0436\u0434\u0443 \u0434\u0432\u0443\u043C\u044F \u043F\u043E\u043B\u044C\ - \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438 \u043C\u043E\u0436\ - \u0435\u0442 \u0431\u044B\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E\ - \ \u043E\u0434\u0438\u043D \u043B\u0438\u0447\u043D\u044B\u0439 \u0447\u0430\ - \u0442.\n" - operationId: createMessage - requestBody: - content: - application/json: - example: - message: - content: "\u0412\u0447\u0435\u0440\u0430 \u043C\u044B \u043F\u0440\ - \u043E\u0434\u0430\u043B\u0438 756 \u0444\u0443\u0442\u0431\u043E\ - \u043B\u043E\u043A (\u0447\u0442\u043E \u043D\u0430 10% \u0431\u043E\ - \u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432 \u043F\u0440\ - \u043E\u0448\u043B\u043E\u0435 \u0432\u043E\u0441\u043A\u0440\u0435\ - \u0441\u0435\u043D\u044C\u0435)" - entity_id: 198 - entity_type: discussion - schema: - properties: - message: - $ref: '#/components/schemas/CreateMessage' - type: object - required: true - responses: - '201': - content: - application/json: - example: - data: - buttons: [] - chat_id: 198 - content: "\u0412\u0447\u0435\u0440\u0430 \u043C\u044B \u043F\u0440\ - \u043E\u0434\u0430\u043B\u0438 756 \u0444\u0443\u0442\u0431\u043E\ - \u043B\u043E\u043A (\u0447\u0442\u043E \u043D\u0430 10% \u0431\ - \u043E\u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432 \u043F\ - \u0440\u043E\u0448\u043B\u043E\u0435 \u0432\u043E\u0441\u043A\u0440\ - \u0435\u0441\u0435\u043D\u044C\u0435)" - created_at: 2020-06-08 09:32:57+00:00 - entity_id: 198 - entity_type: discussion - files: [] - forwarding: null - id: 194275 - parent_message_id: null - thread: null - user_id: 12 - schema: - properties: - data: - $ref: '#/components/schemas/Message' - type: object - description: Successful - '400': - content: - application/json: - examples: - INVALID FIELD VALUE: - summary: invalid field value - value: - errors: - - code: exclusion - key: entity_type - message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ - \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" - value: chat - REQUIRED FIELD BLANK: - summary: required fields blank - value: - errors: - - code: blank - key: content - message: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ - \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ - \u0442\u044B\u043C" - value: null - schema: - $ref: '#/components/schemas/BadRequest' - description: Bad Request - '404': - content: - application/json: - example: - errors: - - code: not_found - key: entyti_id - message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438" - value: 1 - schema: - $ref: '#/components/schemas/Errors' - description: Not Found - summary: "\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u043E\u0432\ - \u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F" - tags: - - messages - /messages/{id}: - get: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0438\u043D\u0444\u043E\u0440\u043C\ - \u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\ - \u0438\u0438.\n\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\ - \u0438\u044F \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0432\ - \u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\ - \ \u0437\u043D\u0430\u0442\u044C \u0435\u0433\u043E id \u0438 \u0443\u043A\ - \u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\ - \u0440\u043E\u0441\u0430.\n" - operationId: getMessage - parameters: - - in: path - name: id - required: true - schema: - title: id - type: integer - responses: - '200': - content: - application/json: - example: - data: - buttons: [] - chat_id: 198 - content: "\u0412\u0447\u0435\u0440\u0430 \u043C\u044B \u043F\u0440\ - \u043E\u0434\u0430\u043B\u0438 756 \u0444\u0443\u0442\u0431\u043E\ - \u043B\u043E\u043A (\u0447\u0442\u043E \u043D\u0430 10% \u0431\ - \u043E\u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432 \u043F\ - \u0440\u043E\u0448\u043B\u043E\u0435 \u0432\u043E\u0441\u043A\u0440\ - \u0435\u0441\u0435\u043D\u044C\u0435)" - created_at: 2020-06-08 09:32:57+00:00 - entity_id: 198 - entity_type: discussion - files: - - file_type: file - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - url: "https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934-\n\ - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max-\n\ - \ age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC\n\ - \ -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_\n\ - \ request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=\n\ - \ host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8\n" - forwarding: null - id: 194275 - parent_message_id: 194274 - thread: - chat_id: 1949863 - id: 29873 - user_id: 12 - schema: - properties: - data: - $ref: '#/components/schemas/Message' - type: object - description: Successfull - '404': - content: - application/json: - example: - errors: - - code: not_found - key: id - message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438" - value: 0 - schema: - $ref: '#/components/schemas/NotFound' - description: Not Found - summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0438\u043D\ - \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u043E\ - \u0431\u0449\u0435\u043D\u0438\u0438" - tags: - - messages - put: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0440\u0435\ - \u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0441\ - \u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0438\u043B\u0438 \u043A\ - \u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F." - operationId: editMessage - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0431\u0435\u0441\u0435\u0434\u044B \u0438\u043B\u0438 \u043A\u0430\ - \u043D\u0430\u043B\u0430." - in: path - name: id - required: true - schema: - type: integer - requestBody: - content: - application/json: - schema: - properties: - message: - $ref: '#/components/schemas/EditMessages' - type: object - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043D\ - \u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432 \u0442\ - \u0435\u0433\u043E\u0432, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\ - \u0442\u0430\u043D\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u043D\u0438\ - \u043A\u0430\u043C\u0438" - responses: - '200': - content: - application/json: - schema: - properties: - data: - description: "\u0421\u043E\u0437\u0434\u0430\u043D\u043D\u043E\ - \u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435" - items: - $ref: '#/components/schemas/Message' - type: array - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0442\u0440\ - \u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043E" - '400': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ErrorsCode' - type: array - description: "\u041D\u0435\u043B\u044C\u0437\u044F \u043F\u043E\u043A\u0438\ - \u043D\u0443\u0442\u044C \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\ - \u044C\u043D\u044B\u0439 \u0447\u0430\u0442" - '404': - content: - application/json: - schema: - items: - $ref: '#/components/schemas/ErrorsCode' - type: array - description: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043D\ - \u0430\u0439\u0442\u0438" - summary: "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\ - \u043D\u0438\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F" - tags: - - message - /messages/{id}/reactions: - delete: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0443\u0434\ - \u0430\u043B\u0435\u043D\u0438\u044F \u0440\u0435\u0430\u043A\u0446\u0438\u0438\ - \ \u043D\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435. \u0423\ - \u0434\u0430\u043B\u0438\u0442\u044C \u043C\u043E\u0436\u043D\u043E \u0442\ - \u043E\u043B\u044C\u043A\u043E \u0442\u0435 \u0440\u0435\u0430\u043A\u0446\ - \u0438\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u044B\u043B\ - \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u044B \u0430\ - \u0432\u0442\u043E\u0440\u0438\u0437\u043E\u0432\u0430\u043D\u043D\u044B\u043C\ - \ \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\ - \u043C.\n" - operationId: deleteMessageReactions - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F." - in: path - name: id - required: true - schema: - type: integer - - description: "Emoji, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043D\u0443\ - \u0436\u043D\u043E \u0443\u0434\u0430\u043B\u0438\u0442\u044C." - in: query - name: code - required: true - schema: - type: string - responses: - '204': - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E\u0435 \u0432\u044B\ - \u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u0437\u0430\u043F\u0440\ - \u043E\u0441\u0430, \u0442\u0435\u043B\u043E \u043E\u0442\u0432\u0435\u0442\ - \u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ - ." - '400': - content: - application/json: - examples: - blank_field: - summary: "\u041F\u043E\u043B\u0435 code \u043F\u0443\u0441\u0442\ - \u043E\u0435" - value: - errors: - - code: blank - key: code - message: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u043C\u043E\ - \u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\u0441\ - \u0442\u044B\u043C" - value: '' - exclusion: - summary: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\ - \u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\ - \ \u044D\u043C\u043E\u0434\u0437\u0438" - value: - errors: - - code: exclusion - key: code - message: "\u041F\u043E\u043B\u0435 \u0438\u043C\u0435\u0435\u0442\ - \ \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\ - \u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435" - value: invalid_emoji - schema: - properties: - errors: - description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ - \u0438\u0431\u043E\u043A \u0432 \u0437\u0430\u043F\u0440\u043E\ - \u0441\u0435." - items: - properties: - code: - description: "\u0412\u043D\u0443\u0442\u0440\u0435\u043D\ - \u043D\u0438\u0439 \u043A\u043E\u0434 \u043E\u0448\u0438\ - \u0431\u043A\u0438." - type: string - key: - description: "\u041A\u043B\u044E\u0447 \u043F\u0430\u0440\ - \u0430\u043C\u0435\u0442\u0440\u0430, \u0432 \u043A\u043E\ - \u0442\u043E\u0440\u043E\u043C \u043F\u0440\u043E\u0438\ - \u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\ - \u043A\u0430." - type: string - message: - description: "\u0422\u0435\u043A\u0441\u0442\u043E\u0432\ - \u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\ - \u0435 \u043E\u0448\u0438\u0431\u043A\u0438." - type: string - payload: - description: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\ - \u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0438\u043D\ - \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E\ - \u0431 \u043E\u0448\u0438\u0431\u043A\u0435." - type: object - value: - description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ - \u0435 \u043A\u043B\u044E\u0447\u0430, \u0432\u044B\u0437\ - \u0432\u0430\u0432\u0448\u0435\u0435 \u043E\u0448\u0438\ - \u0431\u043A\u0443." - type: string - type: object - type: array - type: object - description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\ - \u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\ - ." - '404': - content: - application/json: - examples: - not_found: - summary: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - \ \u0438\u043B\u0438 \u0440\u0435\u0430\u043A\u0446\u0438\u044F\ - \ \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B" - value: - errors: - - code: not_found - key: reaction - message: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C\ - \ \u043D\u0430\u0439\u0442\u0438 \u0440\u0435\u0430\u043A\u0446\ - \u0438\u044E" - value: "\U0001F60A" - schema: - properties: - errors: - description: "\u0421\u043F\u0438\u0441\u043E\u043A \u043E\u0448\ - \u0438\u0431\u043E\u043A." - items: - properties: - code: - type: string - key: - type: string - message: - type: string - payload: - type: object - value: - type: string - type: object - type: array - type: object - description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0438\ - \u043B\u0438 \u0440\u0435\u0430\u043A\u0446\u0438\u044F \u043D\u0435 \u043D\ - \u0430\u0439\u0434\u0435\u043D\u044B." - summary: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0440\u0435\u0430\ - \u043A\u0446\u0438\u0438" - tags: - - reactions to messages - get: - description: "\u042D\u0442\u043E\u0442 \u043C\u0435\u0442\u043E\u0434 \u043F\ - \u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u043F\u043E\u043B\u0443\u0447\ - \u0438\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u0432\u0441\u0435\ - \u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439, \u043E\u0441\u0442\u0430\ - \u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\ - \u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438 \u043D\u0430 \u0443\u043A\ - \u0430\u0437\u0430\u043D\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\ - \u043D\u0438\u0435.\n" - operationId: getMessageReactions - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F, \u0441\u043F\ - \u0438\u0441\u043E\u043A \u0440\u0435\u0430\u043A\u0446\u0438\u0439 \u043D\ - \u0430 \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043D\u0443\u0436\u043D\ - \u043E \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C." - in: path - name: id - required: true - schema: - type: integer - requestBody: - content: - application/json: - schema: - properties: - page: - default: 1 - description: "\u041D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u0430\ - \u043D\u0438\u0446\u044B \u0432\u044B\u0431\u043E\u0440\u043A\u0438\ - \ (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\ - \u044E 1)." - type: integer - per: - default: 50 - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\ - \u043E \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\ - \u044B\u0445 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439\ - \ \u0437\u0430 \u043E\u0434\u0438\u043D \u0437\u0430\u043F\u0440\ - \u043E\u0441 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\ - \u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\u0438\u043C\u0443\ - \u043C 50)." - maximum: 50 - type: integer - type: object - required: false - responses: - '200': - content: - application/json: - schema: - properties: - data: - items: - $ref: '#/components/schemas/Reaction' - type: array - type: object - description: "\u0421\u043F\u0438\u0441\u043E\u043A \u0440\u0435\u0430\u043A\ - \u0446\u0438\u0439 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D." - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/BadRequest' - description: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441." - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\ - \u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E." - summary: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0430\u043A\ - \u0442\u0443\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\ - \u043A\u0430 \u0440\u0435\u0430\u043A\u0446\u0438\u0439." - tags: - - reactions to messages - post: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0434\u043E\ - \u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0440\u0435\u0430\u043A\u0446\ - \u0438\u0438 \u043D\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ - \u0435. **\u041B\u0438\u043C\u0438\u0442\u044B \u0440\u0435\u0430\u043A\u0446\ - \u0438\u0439:** - \u041A\u0430\u0436\u0434\u044B\u0439 \u043F\u043E\u043B\u044C\ - \u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043C\u043E\u0436\u0435\u0442\ - \ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043D\u0435\ - \ \u0431\u043E\u043B\u0435\u0435 20 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\ - \u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439 \u043D\u0430\ - \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435. - \u0421\u043E\u043E\ - \u0431\u0449\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\u0435\u0442 \u0438\ - \u043C\u0435\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 30 \u0443\ - \u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0445 \u0440\u0435\u0430\u043A\ - \u0446\u0438\u0439. - \u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - \ \u043C\u043E\u0436\u0435\u0442 \u0438\u043C\u0435\u0442\u044C \u043D\u0435\ - \ \u0431\u043E\u043B\u0435\u0435 1000 \u0440\u0435\u0430\u043A\u0446\u0438\ - \u0439.\n" - operationId: postMessageReactions - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F." - in: path - name: id - required: true - schema: - type: integer - requestBody: - content: - application/json: - schema: - properties: - code: - description: "Emoji \u0432 \u0441\u0442\u0440\u043E\u043A\u043E\u0432\ - \u043E\u043C \u0444\u043E\u0440\u043C\u0430\u0442\u0435 \u0434\ - \u043B\u044F \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\ - \u044F \u0440\u0435\u0430\u043A\u0446\u0438\u0438." - type: string - required: - - code - type: object - required: true - responses: - '204': - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u043E\u0435 \u0432\u044B\ - \u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u0437\u0430\u043F\u0440\ - \u043E\u0441\u0430, \u0442\u0435\u043B\u043E \u043E\u0442\u0432\u0435\u0442\ - \u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ - ." - '400': - content: - application/json: - examples: - blank_field: - summary: "\u041F\u043E\u043B\u0435 code \u043F\u0443\u0441\u0442\ - \u043E\u0435" - value: - error: blank - exclusion: - summary: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\ - \u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\ - \ \u044D\u043C\u043E\u0434\u0437\u0438" - value: - error: exclusion - schema: - properties: - error: - description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ - \ \u043E\u0448\u0438\u0431\u043A\u0438." - type: string - type: object - description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\ - \u0434\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\ - ." - '403': - content: - application/json: - examples: - general_limit: - summary: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043E\ - \u0431\u0449\u0438\u0439 \u043B\u0438\u043C\u0438\u0442 \u0440\ - \u0435\u0430\u043A\u0446\u0438\u0439 \u043D\u0430 \u0441\u043E\ - \u043E\u0431\u0449\u0435\u043D\u0438\u0435" - value: - error: general_limit - message: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - \ \u043C\u043E\u0436\u0435\u0442 \u0441\u043E\u0434\u0435\u0440\ - \u0436\u0430\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\ - \u0435 1000 \u0440\u0435\u0430\u043A\u0446\u0438\u0439." - unique_limit: - summary: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043B\ - \u0438\u043C\u0438\u0442 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\ - \u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439\ - \ \u043D\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ - \u0435" - value: - error: unique_limit - message: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - \ \u043C\u043E\u0436\u0435\u0442 \u0441\u043E\u0434\u0435\u0440\ - \u0436\u0430\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\ - \u0435 30 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\ - \u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439." - user_limit: - summary: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043B\ - \u0438\u043C\u0438\u0442 \u0443\u043D\u0438\u043A\u0430\u043B\u044C\ - \u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\u0439\ - \ \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\ - \u043B\u044F" - value: - error: user_limit - message: "\u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0434\ - \u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0431\ - \u043E\u043B\u0435\u0435 20 \u0443\u043D\u0438\u043A\u0430\u043B\ - \u044C\u043D\u044B\u0445 \u0440\u0435\u0430\u043A\u0446\u0438\ - \u0439." - schema: - properties: - error: - description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ - \ \u043E\u0448\u0438\u0431\u043A\u0438." - type: string - type: object - description: "\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D\u0438\u0435\ - \ \u043B\u0438\u043C\u0438\u0442\u043E\u0432 \u043F\u043E \u0440\u0435\ - \u0430\u043A\u0446\u0438\u044F\u043C." - '404': - content: - application/json: - examples: - not_found: - summary: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\ - \ \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\ - \u0435\u0442" - value: - error: not_found - schema: - properties: - error: - description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\ - \u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E\ - ." - type: string - type: object - description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\ - \u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E." - summary: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\ - \u0435\u0430\u043A\u0446\u0438\u0438" - tags: - - reactions to messages - /messages/{id}/thread: - post: - description: "\u042D\u0442\u043E\u0442 \u043C\u0435\u0442\u043E\u0434 \u043F\ - \u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0441\u043E\u0437\u0434\u0430\ - \u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u0442\u0440\u0435\u0434 \u043A\ - \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044E. \u0415\u0441\u043B\ - \u0438 \u0443 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0443\ - \u0436\u0435 \u0431\u044B\u043B \u0441\u043E\u0437\u0434\u0430\u043D \u0442\ - \u0440\u0435\u0434, \u0442\u043E \u0432 \u043E\u0442\u0432\u0435\u0442\u0435\ - \ \u0432\u0435\u0440\u043D\u0451\u0442\u0441\u044F \u0438\u043D\u0444\u043E\ - \u0440\u043C\u0430\u0446\u0438\u044F \u043E\u0431 \u0443\u0436\u0435 \u0441\ - \u043E\u0437\u0434\u0430\u043D\u043D\u043E\u043C \u0440\u0430\u043D\u0435\u0435\ - \ \u0442\u0440\u0435\u0434\u0435.\n" - operationId: createThread - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F, \u043A \u043A\ - \u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u0441\u043E\u0437\u0434\u0430\ - \u0435\u0442\u0441\u044F \u0442\u0440\u0435\u0434." - in: path - name: id - required: true - schema: - type: integer - responses: - '200': - content: - application/json: - schema: - properties: - data: - properties: - chat_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ - \u043A\u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430\ - \ \u0442\u0440\u0435\u0434\u0430." - type: integer - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ - \u043A\u0430\u0442\u043E\u0440 \u0441\u043E\u0437\u0434\u0430\ - \u043D\u043D\u043E\u0433\u043E \u0442\u0440\u0435\u0434\u0430\ - ." - type: integer - message_chat_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ - \u043A\u0430\u0442\u043E\u0440 \u0447\u0430\u0442\u0430\ - \ \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\ - ." - type: integer - message_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ - \u043A\u0430\u0442\u043E\u0440 \u0441\u043E\u043E\u0431\u0449\ - \u0435\u043D\u0438\u044F, \u043A \u043A\u043E\u0442\u043E\ - \u0440\u043E\u043C\u0443 \u0431\u044B\u043B \u0441\u043E\ - \u0437\u0434\u0430\u043D \u0442\u0440\u0435\u0434." - type: integer - updated_at: - description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\ - \u0435\u043C\u044F \u043E\u0431\u043D\u043E\u0432\u043B\u0435\ - \u043D\u0438\u044F \u0442\u0440\u0435\u0434\u0430 (ISO-8601,\ - \ UTC+0) \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435\ - \ YYYY-MM-DDThh:mm:ss.sssZ.\n" - format: date-time - type: string - type: object - type: object - description: "\u0422\u0440\u0435\u0434 \u0443\u0441\u043F\u0435\u0448\u043D\ - \u043E \u0441\u043E\u0437\u0434\u0430\u043D \u0438\u043B\u0438 \u0432\u043E\ - \u0437\u0432\u0440\u0430\u0449\u0435\u043D\u044B \u0434\u0430\u043D\u043D\ - \u044B\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\ - \u0435\u0433\u043E \u0442\u0440\u0435\u0434\u0430." - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/BadRequest' - description: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441." - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - description: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\ - \u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E." - summary: "\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u043E\u0432\ - \u043E\u0433\u043E \u0442\u0440\u0435\u0434\u0430" - tags: - - comments - /profile/status: - delete: - description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\ - \u043F\u0440\u043E\u0441\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\ - \u0443\u044E\u0442\n" - operationId: delStatus - responses: - '204': - content: {} - description: "\u041E\u0431\u044A\u0435\u043A\u0442 \u0443\u0441\u043F\u0435\ - \u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D, \u0442\u0435\u043B\ - \u043E \u043E\u0442\u0432\u0435\u0442\u0430 \u043E\u0442\u0441\u0443\u0442\ - \u0441\u0442\u0432\u0443\u0435\u0442" - summary: "\u0443\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0441\u0432\u043E\ - \u0435\u0433\u043E \u0441\u0442\u0430\u0442\u0443\u0441\u0430" - tags: - - status - get: - description: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\ - \u043F\u0440\u043E\u0441\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\ - \u0443\u044E\u0442\n" - operationId: getStatus - responses: - '200': - content: - application/json: - schema: - properties: - data: - $ref: '#/components/schemas/Status' - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0438\u043D\ - \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0441\u0432\u043E\ - \u0435\u043C \u0441\u0442\u0430\u0442\u0443\u0441\u0435" - tags: - - status - put: - description: "\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u043E\u0432\ - \u043E\u0433\u043E \u0441\u0442\u0430\u0442\u0443\u0441\u0430.\n" - operationId: putStatus - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryStatus' - required: true - responses: - '201': - content: - application/json: - schema: - properties: - data: - $ref: '#/components/schemas/Status' - type: object - description: "\u041E\u0431\u044A\u0435\u043A\u0442 \u0441\u043E\u0437\u0434\ - \u0430\u043D" - '400': - content: - application/json: - examples: - BLANK: - description: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\ - \u043D\u043E\u0435 \u043F\u043E\u043B\u0435 (\u043D\u0435 \u043C\ - \u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0443\ - \u0441\u0442\u044B\u043C)" - summary: blank - value: - detail: BLANK - INVALID: - description: "\u041F\u043E\u043B\u0435 \u043D\u0435 \u0441\u043E\ - \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442\ - \ \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C (\u043F\u043E\ - \u044F\u0441\u043D\u0435\u043D\u0438\u044F \u0432\u044B \u043F\ - \u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u0432 \u043F\u043E\ - \u043B\u0435 message)" - summary: invalid - value: - detail: INVALID - TOO_LONG: - description: "\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\ - \u0438\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\ - \u0438\u0435 (\u043F\u043E\u044F\u0441\u043D\u0435\u043D\u0438\ - \u044F \u0432\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\ - \u0435 \u0432 \u043F\u043E\u043B\u0435 message)" - summary: too_long - value: - detail: TOO_LONG - WRONG_EMOJI: - description: "Emoji \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043D\ - \u0435 \u043C\u043E\u0436\u0435\u0442 \u0441\u043E\u0434\u0435\ - \u0440\u0436\u0430\u0442\u044C \u0437\u043D\u0430\u0447\u0435\u043D\ - \u0438\u044F \u043E\u0442\u043B\u0438\u0447\u043D\u044B\u0435\ - \ \u043E\u0442 Emoji \u0441\u0438\u043C\u0432\u043E\u043B\u0430" - summary: wrong_emoji - value: - detail: WRONG_EMOJI - schema: - $ref: '#/components/schemas/BadRequest' - description: BadRequest - summary: "\u043D\u043E\u0432\u044B\u0439 \u0441\u0442\u0430\u0442\u0443\u0441" - tags: - - status - /tasks: - post: - description: "\u041F\u0440\u0438 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0438\ - \ \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F \u043E\ - \u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0443\u0441\ - \u043B\u043E\u0432\u0438\u0435\u043C \u044F\u0432\u043B\u044F\u0435\u0442\u0441\ - \u044F \u0443\u043A\u0430\u0437\u0430\u043D\u0438\u044F \u0442\u0438\u043F\ - \u0430 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F\ - : \u0437\u0432\u043E\u043D\u043E\u043A, \u0432\u0441\u0442\u0440\u0435\u0447\ - \u0430, \u043F\u0440\u043E\u0441\u0442\u043E\u0435 \u043D\u0430\u043F\u043E\ - \u043C\u0438\u043D\u0430\u043D\u0438\u0435, \u0441\u043E\u0431\u044B\u0442\ - \u0438\u0435 \u0438\u043B\u0438 \u043F\u0438\u0441\u044C\u043C\u043E. \n\u041F\ - \u0440\u0438 \u044D\u0442\u043E\u043C \u043D\u0435 \u0442\u0440\u0435\u0431\ - \u0443\u0435\u0442\u0441\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\ - \u0435\u043B\u044C\u043D\u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\ - \u0435 - \u0432\u044B \u043F\u0440\u043E\u0441\u0442\u043E \u0441\u043E\u0437\ - \u0434\u0430\u0434\u0438\u0442\u0435 \u043D\u0430\u043F\u043E\u043C\u0438\u043D\ - \u0430\u043D\u0438\u0435 \u0441 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\ - \u0441\u0442\u0432\u0443\u044E\u0449\u0438\u043C \u0442\u0435\u043A\u0441\u0442\ - \u043E\u043C.\n\u0415\u0441\u043B\u0438 \u0432\u044B \u0443\u043A\u0430\u0436\ - \u0438\u0442\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043D\ - \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F - \u0442\u043E\ - \ \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u043D\u043E \u0438 \u0441\u0442\ - \u0430\u043D\u0435\u0442 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u043D\ - \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F.\n\u0423 \u043D\ - \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F \u0434\u043E\u043B\ - \u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u0442\u0432\u0435\u0442\ - \u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435, \u0435\u0441\u043B\u0438\ - \ \u0438\u0445 \u043D\u0435 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0442\ - \u044C - \u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043D\u043D\ - \u044B\u043C \u043D\u0430\u0437\u043D\u0430\u0447\u0430\u0435\u0442\u0435\u0441\ - \u044C \u0432\u044B.\n" - operationId: createTask - requestBody: - content: - application/json: - schema: - properties: - task: - properties: - content: - description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ - \ \u043D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\ - \u044F" - type: string - custom_properties: - items: - properties: - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\ - \u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\ - \u044F" - type: integer - value: - description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ - \u0435 \u043F\u043E\u043B\u044F" - type: string - type: object - type: array - due_at: - description: "\u0421\u0440\u043E\u043A \u0432\u044B\u043F\u043E\ - \u043B\u043D\u0435\u043D\u0438\u044F \u043D\u0430\u043F\u043E\ - \u043C\u0438\u043D\u0430\u043D\u0438\u044F (ISO-8601)" - format: date-time - type: string - kind: - description: "\u0422\u0438\u043F \u043D\u0430\u043F\u043E\u043C\ - \u0438\u043D\u0430\u043D\u0438\u044F (call, meeting, reminder,\ - \ event, email)" - type: string - performer_ids: - description: "\u041C\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\ - \u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440\u043E\u0432 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\ - \u0430\u0442\u0435\u043B\u0435\u0439" - items: - type: integer - type: array - priority: - description: "\u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\ - \u0442 (1 - \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\ - \u043D\u0438\u044E, 2 - \u0432\u0430\u0436\u043D\u043E, 3\ - \ - \u043E\u0447\u0435\u043D\u044C \u0432\u0430\u0436\u043D\ - \u043E)" - type: integer - required: - - kind - - content - - due_at - type: object - type: object - required: true - responses: - '201': - content: - application/json: - schema: - properties: - data: - properties: - content: - description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435" - type: string - created_at: - description: "\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\ - \u0435\u043C\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\ - \u044F" - format: date-time - type: string - custom_properties: - items: - properties: - data_type: - description: "\u0422\u0438\u043F \u043F\u043E\u043B\u044F\ - \ (string, number, date \u0438\u043B\u0438 link)" - type: string - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\ - \u0438\u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\ - \u044F" - type: integer - name: - description: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\ - \u0435 \u043F\u043E\u043B\u044F" - type: string - value: - description: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\ - \u0435" - type: string - type: object - type: array - due_at: - description: "\u0421\u0440\u043E\u043A \u0432\u044B\u043F\u043E\ - \u043B\u043D\u0435\u043D\u0438\u044F (ISO-8601)" - format: date-time - type: string - id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ - \u043A\u0430\u0442\u043E\u0440 \u0441\u043E\u0437\u0434\u0430\ - \u043D\u043D\u043E\u0433\u043E \u043D\u0430\u043F\u043E\u043C\ - \u0438\u043D\u0430\u043D\u0438\u044F" - type: integer - kind: - description: "\u0422\u0438\u043F" - type: string - performer_ids: - items: - type: integer - type: array - priority: - description: "\u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\ - \u0442" - type: integer - status: - description: "\u0421\u0442\u0430\u0442\u0443\u0441 \u043D\u0430\ - \u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F" - type: string - user_id: - description: "\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\ - \u043A\u0430\u0442\u043E\u0440 \u043F\u043E\u043B\u044C\u0437\ - \u043E\u0432\u0430\u0442\u0435\u043B\u044F-\u0441\u043E\u0437\ - \u0434\u0430\u0442\u0435\u043B\u044F" - type: integer - type: object - type: object - description: "\u041D\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\ - \u0435 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0441\u043E\u0437\u0434\ - \u0430\u043D\u043E" - '400': - content: - application/json: - schema: - properties: - error: - description: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\ - \ \u043E\u0448\u0438\u0431\u043A\u0438" - type: string - type: object - description: "\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u043F\u0440\ - \u043E\u0441\u0430" - summary: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u0441\u043E\u0437\ - \u0434\u0430\u043D\u0438\u044F \u043D\u043E\u0432\u043E\u0433\u043E \u043D\ - \u0430\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F." - tags: - - reminders - /uploads: - post: - description: "\u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043F\ - \u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B, \u043D\u0435\u043E\u0431\ - \u0445\u043E\u0434\u0438\u043C\u044B\u0435 \u0434\u043B\u044F \u0431\u0435\ - \u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0439 \u0437\u0430\u0433\u0440\u0443\ - \u0437\u043A\u0438 \u0444\u0430\u0439\u043B\u0430." - operationId: getUploads - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u043E\u0442\ - \u0432\u0435\u0442." - summary: "\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\ - \u0434\u043F\u0438\u0441\u0438 \u0438 \u043A\u043B\u044E\u0447\u0430 \u0434\ - \u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0444\u0430\ - \u0439\u043B\u0430" - tags: - - common methods - /users: - get: - description: 'Fetch a paginated list of employees with optional filtering by - query. - - ' - operationId: getEmployees - parameters: - - description: "\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E\ - \ \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u044B\u0445\ - \ \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 \u0437\u0430 \u043E\ - \u0434\u0438\u043D \u0437\u0430\u043F\u0440\u043E\u0441 (\u043F\u043E \u0443\ - \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 50, \u043C\u0430\u043A\u0441\ - \u0438\u043C\u0443\u043C" - in: query - name: per - required: false - schema: - default: 50 - maximum: 50 - type: integer - - description: "\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u044B\ - \u0431\u043E\u0440\u043A\u0438 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\ - \u0430\u043D\u0438\u044E 1)" - in: query - name: page - required: false - schema: - default: 1 - type: integer - - description: "\u041F\u043E\u0438\u0441\u043A\u043E\u0432\u0430\u044F \u0444\ - \u0440\u0430\u0437\u0430 \u0434\u043B\u044F \u0444\u0438\u043B\u044C\u0442\ - \u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\ - \u0430\u0442\u043E\u0432 (\u043F\u043E\u0438\u0441\u043A \u0438\u0434\u0435\ - \u0442 \u043F\u043E \u043F\u043E\u043B\u044F\u043C first_name (\u0438\u043C\ - \u044F), last_name (\u0444\u0430\u043C\u0438\u043B\u0438\u044F),\nemail\ - \ (\u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\u044F \u043F\ - \u043E\u0447\u0442\u0430), phone_number (\u0442\u0435\u043B\u0435\u0444\u043E\ - \u043D) \u0438 nickname (\u043D\u0438\u043A\u043D\u0435\u0439\u043C))\n" - in: query - name: query - required: false - schema: - type: string - responses: - '200': - content: - application/json: - schema: - properties: - data: - items: - $ref: '#/components/schemas/Employee' - type: array - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0430\u043A\ - \u0442\u0443\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u043F\u0438\u0441\ - \u043A\u0430 \u0432\u0441\u0435\u0445 \u0441\u043E\u0442\u0440\u0443\u0434\ - \u043D\u0438\u043A\u043E\u0432 \u043A\u043E\u043C\u043F\u0430\u043D\u0438\u0438" - tags: - - employees - /users/{id}: - get: - description: "\u041C\u0435\u0442\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\ - \u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0438\u043D\u0444\u043E\u0440\u043C\ - \u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u0442\u0440\u0443\u0434\u043D\ - \u0438\u043A\u0435.\n\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\ - \u043D\u0438\u044F \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0430\ - \ \u0432\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\ - \u043E \u0437\u043D\u0430\u0442\u044C \u0435\u0433\u043E id \u0438 \u0443\u043A\ - \u0430\u0437\u0430\u0442\u044C \u0435\u0433\u043E \u0432 URL \u0437\u0430\u043F\ - \u0440\u043E\u0441\u0430.\n" - operationId: getEmployee - parameters: - - description: "\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439\ - \ \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\ - \u0440 \u0441\u043E\u0442\u0440\u0443\u0434\u043A\u0438\u043A\u0430" - in: path - name: id - required: true - schema: - type: integer - responses: - '200': - content: - application/json: - schema: - properties: - data: - $ref: '#/components/schemas/Employee' - type: object - description: "\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u0437\u0430\ - \u043F\u0440\u043E\u0441" - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - description: "\u0421\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A \u043D\ - \u0435 \u043D\u0430\u0439\u0434\u0435\u043D" - summary: "\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0438\u043D\ - \u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u0441\u043E\u0442\ - \u0440\u0443\u0434\u043D\u0438\u043A\u0435" - tags: - - employees -security: -- bearerAuth: [] -servers: -- url: https://api.pachca.com/api/shared/v1 -tags: -- description: Everything about common methods - name: common methods -- description: Everything about employees - name: employees -- description: Everything about status - name: status -- description: Everything about tags - name: tags -- description: Everything about chats and channels - name: chats and channels -- description: Everything about talk and channel participants - name: talk and channel participants -- description: Everything about comments - name: comments -- description: Everything about messages - name: messages -- description: Everything about reactions to messages - name: reactions to messages -- description: Everything about reminders - name: reminders -x-base-url: https://api.pachca.com/api/shared/v1 From f67c52bf262c6b296bb673c990f4b52b12332313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 19:34:27 +0300 Subject: [PATCH 119/296] Deleting sync authclient --- src/generator1/templates/client.py.jinja | 39 ------------------------ 1 file changed, 39 deletions(-) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index 5606fde..586cc16 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -23,7 +23,6 @@ class AuthenticatedClient: _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) token: str @@ -33,60 +32,22 @@ class AuthenticatedClient: def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) if self._async_client is not None: self._async_client.headers.update(headers) return evolve(self, headers={**self._headers, **headers}) def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) if self._async_client is not None: self._async_client.cookies.update(cookies) return evolve(self, cookies={**self._cookies, **cookies}) def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout if self._async_client is not None: self._async_client.timeout = timeout return evolve(self, timeout=timeout) - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._client = httpx.Client( - base_url=self.base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": """Manually the underlying httpx.AsyncClient From 6d9970319305ccb803a67ac097a8b24b674f5554 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 30 Dec 2024 21:09:40 +0300 Subject: [PATCH 120/296] refactored yaml support --- src/generator2/generate_pydantic_model.py | 72 +- src/generator2/openapi_test.yaml | 1544 +++++++++++---------- src/generator2/schema_link_processor.py | 62 +- src/generator2/yaml_processor.py | 9 +- 4 files changed, 921 insertions(+), 766 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 3889ca8..7f3b85b 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -1,6 +1,6 @@ from constants import ENUM_TYPES, PYTHON_TYPES from schema_link_processor import ( - replace_ref_with_schema, simple_replace_ref_with_schema, + new_replace_ref_with_schema, ) @@ -32,6 +32,65 @@ def create_enum(name: str, enum_type: str, fields: list): return enum_class_code +def look_into_schema_new(schema: dict): + schema = new_replace_ref_with_schema(schema) + list_of_properties = [] + nested_properties = [] + enum_properties = [] + required_properties = [] + upper_schema_name = list(schema.keys())[0] + inner_schema = ( + schema.get(upper_schema_name).get('properties') + or schema.get(upper_schema_name).get('items',{}).get('properties') + or schema.get(upper_schema_name).get('items',{}).get('items', {}).get('properties')) + required_properties = schema.get(upper_schema_name).get('required', []) + for property in inner_schema: + inner_body = new_replace_ref_with_schema(inner_schema.get(property)) + if 'enum' in inner_body: + enum_properties.append( + (property, inner_body.get('type'), inner_body['enum']), + ) + inner_schema[property] = inner_body + description = inner_body.get('description', 'No docstring provided') + property_type = ( + PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) + if 'enum' in inner_body: + property_type = f'enum_{property}' + if property_type == 'object': + property_type = property.capitalize() + if property_type == 'array': + list_type = inner_body.get("items").get("type") + list_type = PYTHON_TYPES.get(list_type, list_type) + if list_type == 'object' or list_type == 'array': + list_type = property.capitalize() + property_type = (f'List[{list_type}]') + list_of_properties.append( + ( + property, + property_type, + True if property in required_properties else False, + description, + ), + ) + if ('allOf' in inner_body + or inner_body.get('type') == 'object' + or inner_body.get('type') == 'array' + and inner_body.get('items', {}).get('properties') + or inner_body.get('items', {}).get('items')): + nested_properties.append(property) + for nested in nested_properties: + nested_obj = new_replace_ref_with_schema(inner_schema) + if nested in nested_obj: + look_into_schema_new( + {nested.capitalize(): nested_obj[nested]} + ) + else: + look_into_schema_new(nested_obj) + for enum_class in enum_properties: + print(create_enum(*enum_class)) + print(create_model(upper_schema_name, list_of_properties)) + + def look_into_schema(schema: dict) -> None: """Рекурсивно разбирает схемы. @@ -45,7 +104,8 @@ def look_into_schema(schema: dict) -> None: inner_schema = schema.get(upper_schema_name).get('properties') required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: - inner_body = simple_replace_ref_with_schema(inner_schema.get(property)) + inner_body = new_replace_ref_with_schema(inner_schema.get(property)) + # print(property, inner_body, '777777777777777777777777777777777777777777777777777777777777777777') if 'enum' in inner_body: enum_properties.append( (property, inner_body.get('type'), inner_body['enum']), @@ -57,6 +117,7 @@ def look_into_schema(schema: dict) -> None: property_type = f'enum_{property}' if property_type == 'object': property_type = property.capitalize() + # print(inner_body, '33333333333333333333333333333333333333333333333333333333333333') if property_type == 'array': list_type = inner_body.get("items").get("type") list_type = PYTHON_TYPES.get(list_type, list_type) @@ -71,6 +132,7 @@ def look_into_schema(schema: dict) -> None: description, ), ) + # print(property, inner_body, '=========================================================') if (inner_body.get('type') == 'object' or inner_body.get('type') == 'array' and inner_body.get('items', {}).get('properties') @@ -79,19 +141,19 @@ def look_into_schema(schema: dict) -> None: for nested in nested_properties: if ('items' in inner_schema.get(nested) and inner_schema.get(nested).get('items').get('properties')): - look_into_schema(replace_ref_with_schema( + look_into_schema(new_replace_ref_with_schema( {nested.capitalize(): inner_schema.get(nested).get('items')}), ) elif ('items' in inner_schema.get(nested) and inner_schema.get(nested).get('items').get('items')): - look_into_schema(replace_ref_with_schema( + look_into_schema(new_replace_ref_with_schema( { nested.capitalize(): inner_schema.get(nested).get('items').get('items'), }), ) else: - look_into_schema(replace_ref_with_schema( + look_into_schema(new_replace_ref_with_schema( {nested.capitalize(): inner_schema.get(nested)}), ) for enum_class in enum_properties: diff --git a/src/generator2/openapi_test.yaml b/src/generator2/openapi_test.yaml index 4af6b15..c5a258d 100644 --- a/src/generator2/openapi_test.yaml +++ b/src/generator2/openapi_test.yaml @@ -68,7 +68,7 @@ paths: items: $ref: '#/components/schemas/QueryCommonMethods' '400': - description: Запрашиваемый ресурс не существует + description: Пояснения ошибки content: application/json: schema: @@ -121,7 +121,7 @@ paths: content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: '204': description: Успешный запрос. @@ -195,7 +195,7 @@ paths: data: $ref: '#/components/schemas/Employee' '400': - description: Не удалось найти + description: Пояснения ошибки content: application/json: schema: @@ -258,7 +258,7 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: Запрашиваемый ресурс не существует + description: Пояснения ошибки content: application/json: schema: @@ -339,38 +339,25 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: @@ -407,43 +394,25 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: exclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -487,11 +456,24 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} /chats: post: tags: @@ -509,7 +491,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -521,7 +503,7 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: @@ -557,16 +539,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -674,14 +646,14 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -701,16 +673,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -765,8 +727,8 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: @@ -823,13 +785,70 @@ paths: '201': description: Пользователи добавлены '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -867,47 +886,116 @@ paths: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/leave: delete: tags: - talk and channel participants operationId: leaveChat - summary: 'Выход из беседы или канала' + summary: выход из беседы или канала description: |- - Метод для самостоятельного выхода из беседы или канала. + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ parameters: - name: id in: path required: true - description: 'Уникальный идентификатор беседы или канала.' + description: Уникальный идентификатор беседы или канала. schema: type: integer responses: '200': - description: 'Успешно отписан. Тело ответа отсутствует' + description: При безошибочном выполнении запроса тело ответа отсутствуе '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} /messages/{id}/thread: post: tags: @@ -929,40 +1017,44 @@ paths: content: application/json: schema: - type: object - properties: - data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -992,11 +1084,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -1021,46 +1108,48 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion - get: - tags: - - messages - summary: получение списка сообщений чата - description: | + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - messages + summary: получение списка сообщений чата + description: | Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, @@ -1145,41 +1234,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1234,23 +1325,30 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1282,27 +1380,48 @@ paths: items: $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1331,69 +1450,67 @@ paths: responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + - key: string + value: string + message: "Вы можете добавить не более 20 уникальных реакций." + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + - key: string + value: string + message: "Сообщение может содержать не более 30 уникальных реакций." + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + - key: string + value: string + message: "Сообщение может содержать не более 1000 реакций." + code: general_limit + payload: {} delete: tags: - reactions to messages @@ -1417,86 +1534,44 @@ paths: type: string responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - reactions to messages @@ -1538,18 +1613,34 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /tasks: post: tags: @@ -1569,45 +1660,7 @@ paths: type: object properties: task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - title: sotrudnik + $ref: '#/components/schemas/BaseTask' responses: '201': description: Напоминание успешно создано @@ -1617,67 +1670,53 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки - + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: schemas: BaseEmployee: @@ -1723,31 +1762,51 @@ components: type: string description: Массив тегов, привязанных к сотруднику custom_properties: - allOf: - - $ref: '#/components/schemas/СustomProperties' - bot: - type: boolean - description: | + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + bot: + type: boolean + description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - СustomProperties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. Response: type: object properties: @@ -1794,29 +1853,6 @@ components: file: type: string description: Адрес для загрузки файла - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. Status: type: object nullable: true @@ -1850,14 +1886,6 @@ components: type: string example: number description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string Errors: title: Errors type: array @@ -1911,178 +1939,142 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Thread type: object - required: - - entity_id - - content + nullable: true properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id + id: + title: Id type: integer - content: - title: Content - type: string - files: - title: Files - type: array + chat_id: + title: Chat Id + type: integer + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + CreateEditFiles: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array items: type: object - required: - - key - - name - - file_type - - size properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' size: title: Size type: integer - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false + description: Размер файла в байтах, отображаемый пользователю + Files: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array + items: + type: object + properties: + id: + title: Id + type: integer + url: + title: Url + type: string + description: Прямая временная ссылка на скачивание файла EditMessages: type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения files: - type: object + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + BaseMessages: + allOf: + - $ref: '#/components/schemas/EditMessages' + - type: object + required: + - entity_id properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - allOf: - - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object properties: id: title: Id @@ -2090,49 +2082,57 @@ components: chat_id: title: Chat Id type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id + user_id: + title: User Id type: integer + created_at: + title: Created At + type: string + format: date-time + files: + allOf: + - $ref: '#/components/schemas/Files' + title: files + thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + forwarding: + title: Forwarding + type: object nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. Reaction: type: object properties: @@ -2149,81 +2149,7 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2249,6 +2175,39 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. @@ -2262,6 +2221,89 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: array + items: + type: object + properties: + name: + type: string + description: Название поля + data_type: + type: string + description: Тип поля (string, number, date или link) + BaseTask: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 03e0f95..98636ac 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -1,18 +1,63 @@ from yaml_loader import YAML_DICT +def unite_schemas(schemas: list[dict], schema2: dict): + for schema in schemas: + schema2['type'] = schema2.get('type') or schema.get('type') + required_proprties = schema2.get('required', []) + required_proprties.extend(schema.get('required', [])) + schema2['required'] = list(set(required_proprties)) + if schema2['type'] == 'object': + schema2['properties'] = ( + schema2.get('properties', {}) | schema.get('properties', {}) + ) + if schema2['type'] == 'array': + schema2['items'] = ( + schema2.get('items', {}) | schema.get('items', {}) + ) + return schema2 + + def load_schema(path_to_schema: str) -> dict: """Возвращает схему из ссылки.""" schema_name = path_to_schema.split('/')[-1] return YAML_DICT.get('components').get('schemas').get(schema_name) +def new_replace_ref_with_schema(schema: dict): + if '$ref' in schema: + return load_schema(schema['$ref']) + + if 'allOf' in schema: + all_inherits = [new_replace_ref_with_schema(load_schema(ingerit['$ref'])) for ingerit in schema['allOf'] if '$ref' in ingerit] + all_non_inherits = [ingerit for ingerit in schema['allOf'] if '$ref' not in ingerit] + if not all_non_inherits: + all_non_inherits = [{}] + temp = all_non_inherits[0] + temp = unite_schemas(all_inherits, temp) + schema = temp + schema_name = next(iter(schema.keys())) + if 'allOf' in schema[schema_name]: + schema[schema_name] = new_replace_ref_with_schema(schema[schema_name]) + return schema + + def replace_ref_with_schema(schema: dict) -> dict: + """OBSOLETE""" """Заменяет ссылку на схему самой схемой.""" schema_name = next(iter(schema.keys())) + final_result = {} + if 'allOf' == schema_name: + all_inherits = [ingerit for ingerit in schema[schema_name] if '$ref' in ingerit] + # print(all_inherits) + temp = {} + for inherit in all_inherits: + temp |= load_schema(inherit['$ref']) + final_result = temp if 'allOf' in schema[schema_name]: - all_inherits = [ingerit for ingerit in schema[schema_name]['allOf'] if '$ref' in ingerit] - all_non_inherits = [ingerit for ingerit in schema[schema_name]['allOf'] if '$ref' not in ingerit] + if 'allOf' != schema_name: + all_inherits = [ingerit for ingerit in schema[schema_name]['allOf'] if '$ref' in ingerit] + all_non_inherits = [ingerit for ingerit in schema[schema_name]['allOf'] if '$ref' not in ingerit] temp = {} for inherit in all_inherits: inheritable = load_schema(inherit['$ref']) @@ -29,11 +74,17 @@ def replace_ref_with_schema(schema: dict) -> dict: schema[schema_name] = temp else: schema[schema_name] = {'properties': temp} - return schema + final_result = schema + if 'allOf' in final_result: + replace_ref_with_schema(final_result) + if final_result: + return final_result if 'properties' in schema.get(schema_name): current_schema = schema.get(schema_name).get('properties') - if 'items' in schema.get(schema_name): + elif 'items' in schema.get(schema_name): current_schema = schema.get(schema_name).get('items') + else: + return schema for property in current_schema: if '$ref' in current_schema.get(property): current_schema[property] = load_schema( @@ -42,6 +93,7 @@ def replace_ref_with_schema(schema: dict) -> dict: def simple_replace_ref_with_schema(schema: dict) -> dict: + """OBSOLETE""" """Заменяет ссылку на схему самой схемой.""" key = '' if 'properties' in schema: @@ -49,6 +101,8 @@ def simple_replace_ref_with_schema(schema: dict) -> dict: elif 'items' in schema: key = 'items' elif 'allOf' in schema: + # print(schema['allOf'][0]['$ref']) + # print(load_schema(schema['allOf'][0]['$ref']), '=========================') return load_schema(schema['allOf'][0]['$ref']) else: return schema diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 1793520..16a4f75 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -1,7 +1,6 @@ -from typing import Generator from constants import HTTP_METHODS -from generate_pydantic_model import look_into_schema -from schema_link_processor import replace_ref_with_schema, load_schema +from generate_pydantic_model import look_into_schema_new +from schema_link_processor import load_schema from yaml_loader import YAML_DICT @@ -62,11 +61,9 @@ def process_endpoints() -> tuple[list, list]: if schema_has_link else {operation_id.capitalize(): schema.get('schema')} ) - look_into_schema(replace_ref_with_schema(schema)) + look_into_schema_new(schema) print('='*80) - # if operation_id == 'createMessage': - # exit() return path_parameters, query_parameters From 1918d0b5d630d222383ae2eecef8f823021d8e99 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 30 Dec 2024 21:19:48 +0300 Subject: [PATCH 121/296] remove comments --- src/generator2/generate_pydantic_model.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 7f3b85b..be249c9 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -82,8 +82,8 @@ def look_into_schema_new(schema: dict): nested_obj = new_replace_ref_with_schema(inner_schema) if nested in nested_obj: look_into_schema_new( - {nested.capitalize(): nested_obj[nested]} - ) + {nested.capitalize(): nested_obj[nested]} + ) else: look_into_schema_new(nested_obj) for enum_class in enum_properties: @@ -105,7 +105,6 @@ def look_into_schema(schema: dict) -> None: required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: inner_body = new_replace_ref_with_schema(inner_schema.get(property)) - # print(property, inner_body, '777777777777777777777777777777777777777777777777777777777777777777') if 'enum' in inner_body: enum_properties.append( (property, inner_body.get('type'), inner_body['enum']), @@ -117,7 +116,6 @@ def look_into_schema(schema: dict) -> None: property_type = f'enum_{property}' if property_type == 'object': property_type = property.capitalize() - # print(inner_body, '33333333333333333333333333333333333333333333333333333333333333') if property_type == 'array': list_type = inner_body.get("items").get("type") list_type = PYTHON_TYPES.get(list_type, list_type) @@ -132,7 +130,6 @@ def look_into_schema(schema: dict) -> None: description, ), ) - # print(property, inner_body, '=========================================================') if (inner_body.get('type') == 'object' or inner_body.get('type') == 'array' and inner_body.get('items', {}).get('properties') From efacea0e058711051d66efd16b80328b1d419533 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 30 Dec 2024 23:02:54 +0300 Subject: [PATCH 122/296] fixed inheritance order, parents no more overwrite children --- src/generator2/openapi_test.yaml | 2 +- src/generator2/schema_link_processor.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/generator2/openapi_test.yaml b/src/generator2/openapi_test.yaml index c5a258d..eb033d7 100644 --- a/src/generator2/openapi_test.yaml +++ b/src/generator2/openapi_test.yaml @@ -1660,7 +1660,7 @@ paths: type: object properties: task: - $ref: '#/components/schemas/BaseTask' + $ref: '#/components/schemas/Task' responses: '201': description: Напоминание успешно создано diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 98636ac..6e1881a 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -9,12 +9,17 @@ def unite_schemas(schemas: list[dict], schema2: dict): schema2['required'] = list(set(required_proprties)) if schema2['type'] == 'object': schema2['properties'] = ( - schema2.get('properties', {}) | schema.get('properties', {}) + schema.get('properties', {}) | schema2.get('properties', {}) ) if schema2['type'] == 'array': - schema2['items'] = ( - schema2.get('items', {}) | schema.get('items', {}) - ) + if 'items' in schema2 and schema2['items'].get('properties'): + schema2['items']['properties'] = ( + schema.get('items').get('properties') | schema2.get('items').get('properties') + ) + else: + schema2['items'] = ( + schema.get('items', {}) | schema2.get('items', {}) + ) return schema2 From 0e1cecffdff9a4d5e4e37652f91a5ecb0141063c Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 30 Dec 2024 23:32:59 +0300 Subject: [PATCH 123/296] fixed typehint in models based on inherited schemas --- src/generator2/generate_pydantic_model.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index be249c9..dd08e72 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -54,6 +54,8 @@ def look_into_schema_new(schema: dict): description = inner_body.get('description', 'No docstring provided') property_type = ( PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) + if property_type is None: + property_type = [item.get('type') for item in inner_body.get('allOf') if '$ref' not in item][0] if 'enum' in inner_body: property_type = f'enum_{property}' if property_type == 'object': From 86da748e116762ee6dcff6a163f66b15ba501efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 30 Dec 2024 23:46:25 +0300 Subject: [PATCH 124/296] finish static_metod --- src/generator1/client_servis.py | 10 +- src/generator1/script.py | 1 + src/generator1/templates/client.py.jinja | 125 ++++++++++++++++-- .../templates/endpoint_module.py.jinja | 8 +- 4 files changed, 125 insertions(+), 19 deletions(-) diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index f1a9b65..da87d93 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -1,9 +1,13 @@ import httpx -from typing import Any, Dict +from typing import Any class HttpClient: @staticmethod - async def request(method: str, url: str, **kwargs: Any) -> httpx.Response: + async def send_request(method: str, url: str, token: str, **kwargs: Any) -> httpx.Response: + headers = kwargs.get('headers', {}) + headers['Authorization'] = f"Bearer {token}" + kwargs['headers'] = headers + async with httpx.AsyncClient() as client: response = await client.request(method, url, **kwargs) - return response + return response diff --git a/src/generator1/script.py b/src/generator1/script.py index 81d609d..d4771f3 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -77,6 +77,7 @@ def get_all_api_functions_and_imports(api_dir): file.write(types_imports_str + "\n\n") if other_imports: file.write("\n".join(other_imports) + "\n\n") + file.write("from .client_serv import HttpClient" + "\n\n") # file.write("from .static_client import StaticClient\n\n") file.write(client_template.render(endpoints=endpoints)) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index d3a5fe9..b528a11 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -1,12 +1,12 @@ import datetime -import httpx -from .client_serv import HttpClient import ssl from typing import Any, Union, Optional from attrs import define, field, evolve +import httpx +{% from "macros/client_macros.py.jinja" import httpx_args_docstring %} @define class Client: @@ -40,7 +40,11 @@ class Client: """ {% macro attributes() %} raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") + _base_url: str = field( + default="https://api.pachca.com/api/shared/v1", + kw_only=True, + alias="base_url" + ) _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") @@ -149,24 +153,117 @@ class Client: class AuthenticatedClient: """A Client which has been authenticated for use on secured endpoints -{{ httpx_args_docstring() }} + {{ httpx_args_docstring() }} - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - token: The token to use for authentication - prefix: The prefix to use for the Authorization header - auth_header_name: The name of the Authorization header """ -{{ attributes() }} + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field( + default="https://api.pachca.com/api/shared/v1", + kw_only=True, + alias="base_url" + ) + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + token: str prefix: str = "Bearer" auth_header_name: str = "Authorization" -{{ builders("AuthenticatedClient") }} -{{ httpx_stuff("AuthenticatedClient", "self._headers[self.auth_header_name] = f\"{self.prefix} {self.token}\" if self.prefix else self.token") }} + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + class Pachca: """Главный класс библиотеки.""" diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index 2885e08..af078cc 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -6,7 +6,6 @@ import httpx from ...client import AuthenticatedClient, Client from ...types import Response, UNSET from ... import errors -from .client_serv import HttpClient {% for relative in endpoint.relative_imports | sort %} {{ relative }} @@ -113,7 +112,12 @@ async def {{ endpoint.name }}(self, # response = await self.client.get_async_httpx_client().request( # **kwargs #) - response = await HttpClient.request(method=kwargs['method'], url=kwargs['url'], **kwargs) # Используйте статичный метод + base_url = self.client._base_url # Получаем базовый URL из клиента + kwargs['url'] = f"{base_url}{kwargs['url']}" # Формируем полный URL + response = await HttpClient.send_request( + token=self.client.token, + **kwargs + ) return self._build_response_{{ endpoint.name }}( response=response).parsed From 662995a545507cd8717eac48563244a883610202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 31 Dec 2024 09:30:36 +0300 Subject: [PATCH 125/296] finish fix --- src/generator1/script.py | 13 ++----------- src/generator1/templates/client.py.jinja | 2 ++ src/generator1/templates/endpoint_module.py.jinja | 1 + 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/generator1/script.py b/src/generator1/script.py index d4771f3..77ec6fa 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -17,8 +17,6 @@ def extract_functions_and_imports_from_file(file_path) -> None: functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): module = node.module if node.module else '.' - # if module.startswith('.'): - # module = module[1:] # Убираем точку в начале for alias in node.names: if module == 'typing': imports.append(f"from typing import {alias.name}") @@ -26,6 +24,8 @@ def extract_functions_and_imports_from_file(file_path) -> None: imports.append(f"from .models import {alias.name}") elif module == 'types': imports.append(f"from .types import {alias.name}") + elif module == 'client_serv': + imports.append(f"from .client_serv import {alias.name}") else: imports.append(f"from {module} import {alias.name}") @@ -77,18 +77,9 @@ def get_all_api_functions_and_imports(api_dir): file.write(types_imports_str + "\n\n") if other_imports: file.write("\n".join(other_imports) + "\n\n") - file.write("from .client_serv import HttpClient" + "\n\n") - # file.write("from .static_client import StaticClient\n\n") file.write(client_template.render(endpoints=endpoints)) -# cli_servis_template = env.get_template('client_servis.py.jinja') cli_servis_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client_serv.py' - -# with open(cli_servis_path, mode='w', encoding="utf-8") as file: -# file.write(cli_servis_template.render()) -# cli_servis_path = './pachca_servis/pachca_api_open_api_3_0_client/client_servis.py' # Определяем путь к файлу, который нужно скопировать source_file = os.path.join(os.path.dirname(__file__), '..', 'generator1', 'client_servis.py') -# cli_servis_path = os.path.join(os.path.dirname(__file__), 'pachca_servis', 'pachca_api_open_api_3_0_client', 'client_serv.py') -# import pdb;pdb.set_trace()# Копируем файл shutil.copy(source_file, cli_servis_path) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index b528a11..d655157 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -6,6 +6,8 @@ from typing import Any, Union, Optional from attrs import define, field, evolve import httpx +from .client_serv import HttpClient + {% from "macros/client_macros.py.jinja" import httpx_args_docstring %} @define diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index af078cc..9ed0a34 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -7,6 +7,7 @@ from ...client import AuthenticatedClient, Client from ...types import Response, UNSET from ... import errors +from .client_serv import HttpClient {% for relative in endpoint.relative_imports | sort %} {{ relative }} {% endfor %} From 30eb2d1954b1ba66ddac20325b5fe401d39a9167 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 31 Dec 2024 17:58:33 +0500 Subject: [PATCH 126/296] refactoring_swagger_ver1 --- src/openapi.yaml | 472 +++++++++++++++++++++++++---------------------- 1 file changed, 250 insertions(+), 222 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index 4586b40..f3bdd4e 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -43,7 +43,7 @@ paths: - common methods summary: Список дополнительных полей description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type @@ -99,8 +99,11 @@ paths: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -113,8 +116,11 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true @@ -124,7 +130,7 @@ paths: $ref: '#/components/schemas/DirectResponse' responses: '204': - description: Успешный запрос. + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: @@ -132,30 +138,12 @@ paths: summary: получение актуального списка всех сотрудников компании description: | Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/queryParameter' responses: '200': description: Успешный запрос @@ -318,9 +306,11 @@ paths: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -362,26 +352,15 @@ paths: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -421,6 +400,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -428,21 +409,8 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -479,10 +447,10 @@ paths: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -571,68 +539,18 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - required: false - description: Страница выборки (по умолчанию 1) - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time + - $ref: '#/components/parameters/sortParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/availabilityParameter' + - $ref: '#/components/parameters/last_message_at_afterParameter' + - $ref: '#/components/parameters/last_message_at_beforeParameter' responses: '200': description: Запрос отработал как положено, без ошибок @@ -706,7 +624,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -764,23 +682,13 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены @@ -867,21 +775,13 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) @@ -1000,9 +900,9 @@ paths: post: tags: - comments - summary: Создание нового треда + summary: создание нового треда description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. operationId: createThread parameters: - name: id @@ -1017,7 +917,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Thread' + type: object + properties: + data: + $ref: '#/components/schemas/Thread' '400': description: Пояснения ошибки content: @@ -1156,32 +1059,12 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) - schema: - title: per - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - schema: - title: page - type: integer - default: 1 + - $ref: '#/components/parameters/chatParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Successful @@ -1440,13 +1323,7 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. @@ -1490,25 +1367,28 @@ paths: user_limit: description: Превышен лимит уникальных реакций пользователя value: + errors: - key: string value: string - message: "Вы можете добавить не более 20 уникальных реакций." + message: Вы можете добавить не более 20 уникальных реакций. code: user_limit payload: {} unique_limit: description: Превышен лимит уникальных реакций на сообщение value: + errors: - key: string value: string - message: "Сообщение может содержать не более 30 уникальных реакций." + message: Сообщение может содержать не более 30 уникальных реакций. code: unique_limit payload: {} general_limit: description: Превышен общий лимит реакций на сообщение value: + errors: - key: string value: string - message: "Сообщение может содержать не более 1000 реакций." + message: Сообщение может содержать не более 1000 реакций. code: general_limit payload: {} delete: @@ -1526,12 +1406,12 @@ paths: description: Уникальный идентификатор сообщения. schema: type: integer - - name: code - in: query - required: true - description: Emoji, который нужно удалить. - schema: - type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CodeReaction' responses: "204": description: При безошибочном выполнении запроса тело ответа отсутствует @@ -1579,6 +1459,8 @@ paths: summary: получение актуального списка реакций description: | Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path @@ -1586,21 +1468,12 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PerPage' responses: '200': description: Список реакций успешно получен. @@ -1646,8 +1519,10 @@ paths: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1718,7 +1593,148 @@ paths: code: invalid payload: {} components: + parameters: + perParameter50: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + perParameter25: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + pageParameter: + name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + queryParameter: + name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + chatParameter: + name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + sortParameter: + name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + availabilityParameter: + name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + last_message_at_afterParameter: + name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + last_message_at_beforeParameter: + name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time schemas: + PerPage: + type: object + properties: + per: + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + type: integer + default: 50 + maximum: 50 + page: + description: Страница выборки (по умолчанию 1) + type: integer + default: 1 + MembersChat: + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: type: object properties: @@ -2016,7 +2032,7 @@ components: title: Url type: string description: Прямая временная ссылка на скачивание файла - EditMessages: + PreBaseMessages: type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. required: @@ -2026,17 +2042,25 @@ components: type: string description: Текст сообщения default: Текст сообщения - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files buttons: allOf: - $ref: '#/components/schemas/Buttons' title: buttons + EditMessages: + allOf: + - $ref: '#/components/schemas/PreBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files BaseMessages: allOf: - - $ref: '#/components/schemas/EditMessages' + - $ref: '#/components/schemas/PreBaseMessages' - type: object required: - entity_id @@ -2063,6 +2087,10 @@ components: - $ref: '#/components/schemas/BaseMessages' - type: object properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files skip_invite_mentions: title: Skip Invite Mentions type: boolean @@ -2167,6 +2195,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2192,12 +2226,6 @@ components: format: date-time description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ example: '2021-08-28T15:56:53.000Z' - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] last_message_at: type: string format: date-time From 50626dc0becb6c01b4ece227433b47e7ce4bc553 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 31 Dec 2024 20:33:27 +0500 Subject: [PATCH 127/296] refactoring_swagger_ver2 --- src/openapi.yaml | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index f3bdd4e..0d23389 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -41,7 +41,7 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods @@ -66,7 +66,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': description: Пояснения ошибки content: @@ -1395,7 +1395,7 @@ paths: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1686,6 +1686,7 @@ components: format: date-time schemas: PerPage: + title: Per Page type: object properties: per: @@ -1697,7 +1698,8 @@ components: description: Страница выборки (по умолчанию 1) type: integer default: 1 - MembersChat: + MembersChat: + title: Members Chat required: - member_ids type: object @@ -1714,6 +1716,7 @@ components: type: boolean description: Не создавать в чате системное сообщение о добавлении участника GroupTag: + title: Group Tag required: - group_tag_ids type: object @@ -1726,7 +1729,8 @@ components: format: int64 example: [86, 18] description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: + CodeReaction: + title: Code Reaction type: object properties: code: @@ -1736,6 +1740,7 @@ components: required: - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1823,7 +1828,8 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. - Response: + BaseResponse: + title: Base Response type: object properties: Content-Disposition: @@ -1854,16 +1860,18 @@ components: type: string description: Уникальный ключ для загрузки файла FileResponse: + title: File Response allOf: - - $ref: '#/components/schemas/Response' + - $ref: '#/components/schemas/BaseResponse' - type: object properties: direct_url: type: string description: Адрес для загрузки файла DirectResponse: + title: Direct Response allOf: - - $ref: '#/components/schemas/Response' + - $ref: '#/components/schemas/BaseResponse' - type: object properties: file: @@ -1886,7 +1894,8 @@ components: nullable: true description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryCommonMethods: + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1903,7 +1912,6 @@ components: example: number description: тип поля (string, number, date или link) Errors: - title: Errors type: array items: title: Error @@ -1956,7 +1964,7 @@ components: type: string maxLength: 255 BaseThread: - title: Thread + title: Base Thread type: object nullable: true properties: @@ -1983,7 +1991,7 @@ components: description: | Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. BaseFiles: - title: Files + title: Base Files type: array items: type: object @@ -2008,6 +2016,7 @@ components: - 'file' - 'image' CreateEditFiles: + title: Create&Edit Files allOf: - $ref: '#/components/schemas/BaseFiles' - type: array @@ -2032,7 +2041,8 @@ components: title: Url type: string description: Прямая временная ссылка на скачивание файла - PreBaseMessages: + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. required: @@ -2047,8 +2057,9 @@ components: - $ref: '#/components/schemas/Buttons' title: buttons EditMessages: + title: Edit Messages allOf: - - $ref: '#/components/schemas/PreBaseMessages' + - $ref: '#/components/schemas/BeforeBaseMessages' - type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. required: @@ -2059,8 +2070,9 @@ components: - $ref: '#/components/schemas/CreateEditFiles' title: files BaseMessages: + title: Base Messages allOf: - - $ref: '#/components/schemas/PreBaseMessages' + - $ref: '#/components/schemas/BeforeBaseMessages' - type: object required: - entity_id @@ -2083,6 +2095,7 @@ components: default: null description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. CreateMessage: + title: Create Messages allOf: - $ref: '#/components/schemas/BaseMessages' - type: object @@ -2178,6 +2191,7 @@ components: description: | Emoji символ реакции. BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2250,6 +2264,7 @@ components: description: Количество сотрудников, которые имеют этот тег type: integer BaseCustomProperties: + title: Base Custom Properties type: array items: type: object @@ -2261,6 +2276,7 @@ components: type: string description: Значение поля CustomProperties: + title: Custom Properties allOf: - $ref: '#/components/schemas/BaseCustomProperties' - type: array @@ -2274,6 +2290,7 @@ components: type: string description: Тип поля (string, number, date или link) BaseTask: + title: Base Task type: object required: - kind From 53de455bfcae3e8144e43328b742896cff2f3604 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 31 Dec 2024 21:15:00 +0500 Subject: [PATCH 128/296] refactoring_swagger_ver3 --- src/openapi.yaml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index 0d23389..a2ad4d8 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -1767,6 +1767,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1775,6 +1779,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1796,6 +1803,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1909,8 +1921,13 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) + description: тип поля Errors: type: array items: @@ -2288,6 +2305,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) BaseTask: title: Base Task From de1b7bbe4a3a5e76d500327e9274f3600976cea2 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 31 Dec 2024 21:42:26 +0500 Subject: [PATCH 129/296] refactoring_swagger_ver4 --- src/openapi.yaml | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index a2ad4d8..de427cc 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -1406,12 +1406,7 @@ paths: description: Уникальный идентификатор сообщения. schema: type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' + - $ref: '#/components/parameters/reactionParameter' responses: "204": description: При безошибочном выполнении запроса тело ответа отсутствует @@ -1468,12 +1463,8 @@ paths: required: true schema: type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/PerPage' + - $ref: '#/components/parameters/chatParameter' + - $ref: '#/components/parameters/perParameter50' responses: '200': description: Список реакций успешно получен. @@ -1684,20 +1675,14 @@ components: schema: type: string format: date-time + reactionParameter: + name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" schemas: - PerPage: - title: Per Page - type: object - properties: - per: - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - type: integer - default: 50 - maximum: 50 - page: - description: Страница выборки (по умолчанию 1) - type: integer - default: 1 MembersChat: title: Members Chat required: From 77ada6b954be54efa4ff9ff854205d00acfe5fd2 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 31 Dec 2024 21:54:31 +0500 Subject: [PATCH 130/296] refactoring_swagger_ver5 --- src/openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index de427cc..8abb9a9 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -1463,8 +1463,8 @@ paths: required: true schema: type: integer - - $ref: '#/components/parameters/chatParameter' - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Список реакций успешно получен. From 8b87963f262fe9b76bd5e5d45b5bc927e91bf2a2 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Tue, 31 Dec 2024 20:24:12 +0300 Subject: [PATCH 131/296] fixed required proprties in schemas with array and inheritance --- src/generator2/schema_link_processor.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 6e1881a..4b52d78 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -13,6 +13,11 @@ def unite_schemas(schemas: list[dict], schema2: dict): ) if schema2['type'] == 'array': if 'items' in schema2 and schema2['items'].get('properties'): + required_proprties = schema2['items'].get('required', []) + required_proprties.extend(schema['items'].get('required', [])) + schema2['required'] = list(set(required_proprties)) + print(schemas) + print(schema2) schema2['items']['properties'] = ( schema.get('items').get('properties') | schema2.get('items').get('properties') ) From 76822a175b0ad31e5ece6d61b27ceb26a59fba24 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 Jan 2025 01:21:12 +0300 Subject: [PATCH 132/296] HTTP_client generic outline --- src/generator1/client_servis.py | 4 +++- src/generator1/script.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index da87d93..540fb55 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -1,6 +1,8 @@ -import httpx from typing import Any +import httpx + + class HttpClient: @staticmethod async def send_request(method: str, url: str, token: str, **kwargs: Any) -> httpx.Response: diff --git a/src/generator1/script.py b/src/generator1/script.py index 476ecb5..d8e20cf 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -87,8 +87,8 @@ def get_base_url_from_yaml(openapi_yaml): if other_imports: file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints, base_url=base_url)) - -'''Копирование client_servis.py''' + +# Копирование client_servis.py cli_servis_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client_serv.py' # Определяем путь к файлу, который нужно скопировать source_file = os.path.join(os.path.dirname(__file__), '..', 'generator1', 'client_servis.py') From dfb61cbb4e93a862485a842f015667d2416e8d2b Mon Sep 17 00:00:00 2001 From: Aleksey Malkov Date: Thu, 2 Jan 2025 02:12:33 +0300 Subject: [PATCH 133/296] delete tabulations --- src/openapi.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openapi.yaml b/src/openapi.yaml index 8abb9a9..a2bf3a7 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -340,7 +340,7 @@ paths: $ref: '#/components/schemas/Errors' examples: not_found: - description: Не удалось найти + description: Не удалось найти value: errors: - key: string @@ -2028,7 +2028,7 @@ components: size: title: Size type: integer - description: Размер файла в байтах, отображаемый пользователю + description: Размер файла в байтах, отображаемый пользователю Files: allOf: - $ref: '#/components/schemas/BaseFiles' @@ -2042,7 +2042,7 @@ components: url: title: Url type: string - description: Прямая временная ссылка на скачивание файла + description: Прямая временная ссылка на скачивание файла BeforeBaseMessages: title: Before Base Messages type: object From d520f30905ba6a362f7f23491eca79257daf8c4f Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Thu, 2 Jan 2025 11:52:35 +0300 Subject: [PATCH 134/296] support for in parameters for endpoints --- src/generator2/openapi_test.yaml | 528 +++++++++++++----------- src/generator2/schema_link_processor.py | 9 +- src/generator2/yaml_processor.py | 2 + 3 files changed, 295 insertions(+), 244 deletions(-) diff --git a/src/generator2/openapi_test.yaml b/src/generator2/openapi_test.yaml index eb033d7..87dd396 100644 --- a/src/generator2/openapi_test.yaml +++ b/src/generator2/openapi_test.yaml @@ -41,9 +41,9 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type @@ -66,7 +66,7 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': description: Пояснения ошибки content: @@ -99,8 +99,11 @@ paths: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -113,8 +116,11 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true @@ -124,7 +130,7 @@ paths: $ref: '#/components/schemas/DirectResponse' responses: '204': - description: Успешный запрос. + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: @@ -132,30 +138,12 @@ paths: summary: получение актуального списка всех сотрудников компании description: | Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/queryParameter' responses: '200': description: Успешный запрос @@ -318,9 +306,11 @@ paths: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -350,7 +340,7 @@ paths: $ref: '#/components/schemas/Errors' examples: not_found: - description: Не удалось найти + description: Не удалось найти value: errors: - key: string @@ -362,26 +352,15 @@ paths: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -421,6 +400,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -428,21 +409,8 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -479,10 +447,10 @@ paths: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -571,68 +539,18 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - required: false - description: Страница выборки (по умолчанию 1) - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time + - $ref: '#/components/parameters/sortParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/availabilityParameter' + - $ref: '#/components/parameters/last_message_at_afterParameter' + - $ref: '#/components/parameters/last_message_at_beforeParameter' responses: '200': description: Запрос отработал как положено, без ошибок @@ -706,7 +624,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -764,23 +682,13 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены @@ -867,21 +775,13 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) @@ -1000,9 +900,9 @@ paths: post: tags: - comments - summary: Создание нового треда + summary: создание нового треда description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. operationId: createThread parameters: - name: id @@ -1017,7 +917,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Thread' + type: object + properties: + data: + $ref: '#/components/schemas/Thread' '400': description: Пояснения ошибки content: @@ -1156,32 +1059,12 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) - schema: - title: per - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - schema: - title: page - type: integer - default: 1 + - $ref: '#/components/parameters/chatParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Successful @@ -1440,13 +1323,7 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. @@ -1490,32 +1367,35 @@ paths: user_limit: description: Превышен лимит уникальных реакций пользователя value: + errors: - key: string value: string - message: "Вы можете добавить не более 20 уникальных реакций." + message: Вы можете добавить не более 20 уникальных реакций. code: user_limit payload: {} unique_limit: description: Превышен лимит уникальных реакций на сообщение value: + errors: - key: string value: string - message: "Сообщение может содержать не более 30 уникальных реакций." + message: Сообщение может содержать не более 30 уникальных реакций. code: unique_limit payload: {} general_limit: description: Превышен общий лимит реакций на сообщение value: + errors: - key: string value: string - message: "Сообщение может содержать не более 1000 реакций." + message: Сообщение может содержать не более 1000 реакций. code: general_limit payload: {} delete: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1526,12 +1406,7 @@ paths: description: Уникальный идентификатор сообщения. schema: type: integer - - name: code - in: query - required: true - description: Emoji, который нужно удалить. - schema: - type: string + - $ref: '#/components/parameters/reactionParameter' responses: "204": description: При безошибочном выполнении запроса тело ответа отсутствует @@ -1579,6 +1454,8 @@ paths: summary: получение актуального списка реакций description: | Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path @@ -1586,21 +1463,8 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Список реакций успешно получен. @@ -1646,8 +1510,10 @@ paths: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1660,7 +1526,7 @@ paths: type: object properties: task: - $ref: '#/components/schemas/Task' + $ref: '#/components/schemas/BaseTask' responses: '201': description: Напоминание успешно создано @@ -1718,8 +1584,148 @@ paths: code: invalid payload: {} components: + parameters: + perParameter50: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + perParameter25: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + pageParameter: + name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + queryParameter: + name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + chatParameter: + name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + sortParameter: + name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + availabilityParameter: + name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + last_message_at_afterParameter: + name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + last_message_at_beforeParameter: + name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + reactionParameter: + name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1746,6 +1752,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1754,6 +1764,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1775,6 +1788,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1807,7 +1825,8 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. - Response: + BaseResponse: + title: Base Response type: object properties: Content-Disposition: @@ -1838,16 +1857,18 @@ components: type: string description: Уникальный ключ для загрузки файла FileResponse: + title: File Response allOf: - - $ref: '#/components/schemas/Response' + - $ref: '#/components/schemas/BaseResponse' - type: object properties: direct_url: type: string description: Адрес для загрузки файла DirectResponse: + title: Direct Response allOf: - - $ref: '#/components/schemas/Response' + - $ref: '#/components/schemas/BaseResponse' - type: object properties: file: @@ -1870,7 +1891,8 @@ components: nullable: true description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryCommonMethods: + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1884,10 +1906,14 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) + description: тип поля Errors: - title: Errors type: array items: title: Error @@ -1940,7 +1966,7 @@ components: type: string maxLength: 255 BaseThread: - title: Thread + title: Base Thread type: object nullable: true properties: @@ -1967,7 +1993,7 @@ components: description: | Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. BaseFiles: - title: Files + title: Base Files type: array items: type: object @@ -1992,6 +2018,7 @@ components: - 'file' - 'image' CreateEditFiles: + title: Create&Edit Files allOf: - $ref: '#/components/schemas/BaseFiles' - type: array @@ -2001,7 +2028,7 @@ components: size: title: Size type: integer - description: Размер файла в байтах, отображаемый пользователю + description: Размер файла в байтах, отображаемый пользователю Files: allOf: - $ref: '#/components/schemas/BaseFiles' @@ -2015,8 +2042,9 @@ components: url: title: Url type: string - description: Прямая временная ссылка на скачивание файла - EditMessages: + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. required: @@ -2026,17 +2054,27 @@ components: type: string description: Текст сообщения default: Текст сообщения - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files buttons: allOf: - $ref: '#/components/schemas/Buttons' title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files BaseMessages: + title: Base Messages allOf: - - $ref: '#/components/schemas/EditMessages' + - $ref: '#/components/schemas/BeforeBaseMessages' - type: object required: - entity_id @@ -2059,10 +2097,15 @@ components: default: null description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. CreateMessage: + title: Create Messages allOf: - $ref: '#/components/schemas/BaseMessages' - type: object properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files skip_invite_mentions: title: Skip Invite Mentions type: boolean @@ -2150,6 +2193,7 @@ components: description: | Emoji символ реакции. BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2167,6 +2211,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2192,12 +2242,6 @@ components: format: date-time description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ example: '2021-08-28T15:56:53.000Z' - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] last_message_at: type: string format: date-time @@ -2222,6 +2266,7 @@ components: description: Количество сотрудников, которые имеют этот тег type: integer BaseCustomProperties: + title: Base Custom Properties type: array items: type: object @@ -2233,6 +2278,7 @@ components: type: string description: Значение поля CustomProperties: + title: Custom Properties allOf: - $ref: '#/components/schemas/BaseCustomProperties' - type: array @@ -2244,8 +2290,14 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) BaseTask: + title: Base Task type: object required: - kind @@ -2309,4 +2361,4 @@ components: type: http scheme: bearer security: - - bearerAuth: [] + - bearerAuth: [] \ No newline at end of file diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 4b52d78..fd245ca 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -16,8 +16,6 @@ def unite_schemas(schemas: list[dict], schema2: dict): required_proprties = schema2['items'].get('required', []) required_proprties.extend(schema['items'].get('required', [])) schema2['required'] = list(set(required_proprties)) - print(schemas) - print(schema2) schema2['items']['properties'] = ( schema.get('items').get('properties') | schema2.get('items').get('properties') ) @@ -28,9 +26,11 @@ def unite_schemas(schemas: list[dict], schema2: dict): return schema2 -def load_schema(path_to_schema: str) -> dict: +def load_schema(path_to_schema: str, is_parameter: bool = False) -> dict: """Возвращает схему из ссылки.""" schema_name = path_to_schema.split('/')[-1] + if is_parameter: + return YAML_DICT.get('components').get('parameters').get(schema_name) return YAML_DICT.get('components').get('schemas').get(schema_name) @@ -59,7 +59,6 @@ def replace_ref_with_schema(schema: dict) -> dict: final_result = {} if 'allOf' == schema_name: all_inherits = [ingerit for ingerit in schema[schema_name] if '$ref' in ingerit] - # print(all_inherits) temp = {} for inherit in all_inherits: temp |= load_schema(inherit['$ref']) @@ -111,8 +110,6 @@ def simple_replace_ref_with_schema(schema: dict) -> dict: elif 'items' in schema: key = 'items' elif 'allOf' in schema: - # print(schema['allOf'][0]['$ref']) - # print(load_schema(schema['allOf'][0]['$ref']), '=========================') return load_schema(schema['allOf'][0]['$ref']) else: return schema diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 16a4f75..4229ca7 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -31,6 +31,8 @@ def process_endpoints() -> tuple[list, list]: query_parameters = [] if parameters: for parameter in parameters: + if '$ref' in parameter: + parameter = load_schema(parameter['$ref'], is_parameter=1) required = parameter.get('required', False) if required: path_parameters.append( From fb6c094fec56c3aa7a8cfdd05aa1c9ddb22a78f0 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Thu, 2 Jan 2025 14:41:43 +0300 Subject: [PATCH 135/296] add list of lists typehint for buttons --- src/generator2/generate_pydantic_model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index dd08e72..3c3d4d7 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -65,6 +65,8 @@ def look_into_schema_new(schema: dict): list_type = PYTHON_TYPES.get(list_type, list_type) if list_type == 'object' or list_type == 'array': list_type = property.capitalize() + if inner_body.get("items").get("items"): + list_type = f'List[{list_type}]' property_type = (f'List[{list_type}]') list_of_properties.append( ( @@ -82,7 +84,7 @@ def look_into_schema_new(schema: dict): nested_properties.append(property) for nested in nested_properties: nested_obj = new_replace_ref_with_schema(inner_schema) - if nested in nested_obj: + if nested in nested_obj: look_into_schema_new( {nested.capitalize(): nested_obj[nested]} ) From 4188bb2cde7b60719b205218e7d9041a98b2af67 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 Jan 2025 17:58:26 +0300 Subject: [PATCH 136/296] fixed small changes --- src/generator2/openapi.yaml | 2208 +++++++++++++++++---------------- src/generator2/yaml_loader.py | 3 +- 2 files changed, 1174 insertions(+), 1037 deletions(-) diff --git a/src/generator2/openapi.yaml b/src/generator2/openapi.yaml index bb80f7b..87dd396 100644 --- a/src/generator2/openapi.yaml +++ b/src/generator2/openapi.yaml @@ -41,17 +41,20 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type in: query - description: Тип сущности - участник (User) или напоминание (Task). + description: Тип сущности required: true schema: type: string + enum: + - User + - Task responses: '200': description: Успешный запрос @@ -63,30 +66,44 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Поле не может быть пустым value: - detail: BLANK - INCLUSION: - summary: inclusion + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: description: Поле имеет непредусмотренное значение value: - detail: INCLUSION + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /uploads: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -99,50 +116,34 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: '204': - description: Успешный запрос. + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: - employees summary: получение актуального списка всех сотрудников компании description: | - Fetch a paginated list of employees with optional filtering by query. + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/queryParameter' responses: '200': description: Успешный запрос @@ -181,19 +182,32 @@ paths: properties: data: $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /profile/status: get: tags: - status summary: получение информации о своем статусе description: | - Параметры запроса отсутствуют + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. operationId: getStatus responses: '200': @@ -210,14 +224,17 @@ paths: - status summary: новый статус description: | - Создание нового статуса. + Метод для установки себе нового статуса. operationId: putStatus requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/QueryStatus' + type: object + properties: + status: + $ref: '#/components/schemas/Status' responses: '201': description: Объект создан @@ -229,50 +246,71 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Обязательное поле (не может быть пустым) value: - detail: BLANK - TOO_LONG: - summary: too_long + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: description: Слишком длинное значение (пояснения вы получите в поле message) value: - detail: TOO_LONG - INVALID: - summary: invalid + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) value: - detail: INVALID - WRONG_EMOJI: - summary: wrong_emoji + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: description: Emoji статуса не может содержать значения отличные от Emoji символа value: - detail: WRONG_EMOJI + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} delete: tags: - status summary: удаление своего статуса description: | - Параметры запроса отсутствуют + Метод для удаления своего статуса. Параметры запроса отсутствуют. operationId: delStatus responses: '204': - description: Объект успешно удален, тело ответа отсутствует + description: При безошибочном выполнении запроса тело ответа отсутствует content: {} /group_tags/{id}: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -291,62 +329,38 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -359,43 +373,25 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: exclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -404,6 +400,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -411,21 +409,8 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -439,20 +424,33 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} /chats: post: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -461,7 +459,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -473,7 +471,7 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: @@ -509,16 +507,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -551,68 +539,18 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - required: false - description: Страница выборки (по умолчанию 1) - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time + - $ref: '#/components/parameters/sortParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/availabilityParameter' + - $ref: '#/components/parameters/last_message_at_afterParameter' + - $ref: '#/components/parameters/last_message_at_beforeParameter' responses: '200': description: Запрос отработал как положено, без ошибок @@ -626,14 +564,14 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -653,16 +591,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -696,7 +624,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -717,8 +645,8 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: @@ -754,34 +682,81 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -800,73 +775,134 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: 'Выход из беседы или канала' - description: |- - Метод для самостоятельного выхода из беседы или канала. - parameters: - - name: id - in: path - required: true - description: 'Уникальный идентификатор беседы или канала.' - schema: - type: integer - responses: - '200': - description: 'Успешно отписан. Тело ответа отсутствует' - '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /messages/{id}/thread: - post: - tags: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: выход из беседы или канала + description: |- + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '200': + description: При безошибочном выполнении запроса тело ответа отсутствуе + '400': + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: - comments - summary: Создание нового треда + summary: создание нового треда description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. operationId: createThread parameters: - name: id @@ -884,37 +920,44 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -944,11 +987,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -973,41 +1011,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - messages @@ -1019,32 +1059,12 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) - schema: - title: per - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - schema: - title: page - type: integer - default: 1 + - $ref: '#/components/parameters/chatParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Successful @@ -1097,41 +1117,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1186,23 +1208,30 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1234,27 +1263,48 @@ paths: items: $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1273,84 +1323,79 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} delete: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1361,124 +1406,65 @@ paths: description: Уникальный идентификатор сообщения. schema: type: integer - - name: code - in: query - required: true - description: Emoji, который нужно удалить. - schema: - type: string + - $ref: '#/components/parameters/reactionParameter' responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path + description: Уникальный идентификатор сообщения required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Список реакций успешно получен. @@ -1491,25 +1477,43 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /tasks: post: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1522,41 +1526,7 @@ paths: type: object properties: task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля + $ref: '#/components/schemas/BaseTask' responses: '201': description: Напоминание успешно создано @@ -1566,70 +1536,196 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки - + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: + parameters: + perParameter50: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + perParameter25: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + pageParameter: + name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + queryParameter: + name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + chatParameter: + name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + sortParameter: + name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + availabilityParameter: + name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + last_message_at_afterParameter: + name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + last_message_at_beforeParameter: + name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + reactionParameter: + name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1656,6 +1752,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1664,6 +1764,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1685,6 +1788,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1694,48 +1802,6 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - FileResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - direct_url: - type: string - DirectResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1759,45 +1825,74 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. - Status: + BaseResponse: + title: Base Response type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. properties: - emoji: + Content-Disposition: type: string - description: Emoji символ статуса - title: + description: Используемый заголовок + default: attachment + acl: type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object properties: - emoji: + direct_url: type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - QueryCommonMethods: + description: Адрес для загрузки файла + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1811,18 +1906,14 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string + description: тип поля Errors: - title: Errors type: array items: title: Error @@ -1831,18 +1922,23 @@ components: key: title: key type: string + description: Ключ параметра, в котором произошла ошибка value: title: value type: string + description: Значение ключа, которое вызвало ошибку message: title: message type: string + description: Ошибка текстом, который вы можете вывести пользователю code: title: code type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) payload: title: payload type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) Buttons: title: Message Buttons type: array @@ -1869,176 +1965,159 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Base Thread type: object - required: - - entity_id - - content + nullable: true properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id + id: + title: Id type: integer - content: - title: Content - type: string - files: - title: Files - type: array + chat_id: + title: Chat Id + type: integer + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + CreateEditFiles: + title: Create&Edit Files + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array items: type: object - required: - - key - - name - - file_type - - size properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' size: title: Size type: integer - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - EditMessages: + description: Размер файла в байтах, отображаемый пользователю + Files: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array + items: + type: object + properties: + id: + title: Id + type: integer + url: + title: Url + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения - files: - type: object + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object properties: id: title: Id @@ -2046,49 +2125,57 @@ components: chat_id: title: Chat Id type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id + user_id: + title: User Id type: integer + created_at: + title: Created At + type: string + format: date-time + files: + allOf: + - $ref: '#/components/schemas/Files' + title: files + thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + forwarding: + title: Forwarding + type: object nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. Reaction: type: object properties: @@ -2105,81 +2192,8 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2197,6 +2211,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2205,6 +2225,33 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. @@ -2218,9 +2265,100 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + title: Base Custom Properties + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + title: Custom Properties + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: array + items: + type: object + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http scheme: bearer security: - - bearerAuth: [] + - bearerAuth: [] \ No newline at end of file diff --git a/src/generator2/yaml_loader.py b/src/generator2/yaml_loader.py index 482eba1..bb97a36 100644 --- a/src/generator2/yaml_loader.py +++ b/src/generator2/yaml_loader.py @@ -1,7 +1,6 @@ from pathlib import Path -from ruamel.yaml import YAML from constants import PATH_TO_YAML - +from ruamel.yaml import YAML YAML_DICT = YAML(typ='rt').load(Path(PATH_TO_YAML)) From a8b96b9a683996fb03e74e7de08cc4b3849eb15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Fri, 3 Jan 2025 00:20:22 +0300 Subject: [PATCH 137/296] code refactoring --- src/generator2/api_methods.py | 244 ------------------------- src/generator2/bot.py | 59 ++++++ src/generator2/gen_class_pachca.py | 140 --------------- src/generator2/openapi.yaml | 3 +- src/generator2/pachca.py | 18 +- src/generator2/request_methods.py | 250 ++++++++++++++++++++++++++ src/generator2/request_methods_gen.py | 162 +++++++++++++++++ 7 files changed, 482 insertions(+), 394 deletions(-) delete mode 100644 src/generator2/api_methods.py create mode 100644 src/generator2/bot.py delete mode 100644 src/generator2/gen_class_pachca.py create mode 100644 src/generator2/request_methods.py create mode 100644 src/generator2/request_methods_gen.py diff --git a/src/generator2/api_methods.py b/src/generator2/api_methods.py deleted file mode 100644 index fad9fbd..0000000 --- a/src/generator2/api_methods.py +++ /dev/null @@ -1,244 +0,0 @@ -"""Сгенерированные методы запроса.""" - - -async def get_common_methods(self, param_query=None): - """Список дополнительных полей - -Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. -""" - client = await self.get_client() - async with client: - response = await client.get('/custom_properties', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_uploads(self, param_query=None): - """Получение подписи и ключа для загрузки файла - -Возвращает параметры, необходимые для безопасной загрузки файла.""" - client = await self.get_client() - async with client: - response = await client.post('/uploads', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_direct_url(self, param_query=None): - """Получение URL для загрузки - -Отправляет запрос для получения URL для безопасной загрузки файла.""" - client = await self.get_client() - async with client: - response = await client.post('/direct_url', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_employees(self, param_query=None): - """получение актуального списка всех сотрудников компании - -Fetch a paginated list of employees with optional filtering by query. -""" - client = await self.get_client() - async with client: - response = await client.get('/users', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_employee(self, id, param_query=None): - """получение информации о сотруднике - -Метод для получения информации о сотруднике. -Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. -""" - client = await self.get_client() - async with client: - response = await client.get(f'/users/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def del_status(self, param_query=None): - """удаление своего статуса - -Параметры запроса отсутствуют -""" - client = await self.get_client() - async with client: - response = await client.delete('/profile/status', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_tag(self, id, param_query=None): - """Информация о теге - -Параметры запроса отсутствуют -""" - client = await self.get_client() - async with client: - response = await client.get(f'/group_tags/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_tags(self, param_query=None): - """Список тегов сотрудников - -Метод для получения актуального списка тегов сотрудников. -""" - client = await self.get_client() - async with client: - response = await client.get('/group_tags', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_tags_employees(self, id, param_query=None): - """получение актуального списка сотрудников тега - -Метод для получения актуального списка сотрудников тега. -""" - client = await self.get_client() - async with client: - response = await client.get(f'/group_tags/{id}/users', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_chat(self, param_query=None): - """Новая беседа или канал - -Метод для создания новой беседы или нового канала. -При создании беседы или канала вы автоматически становитесь участником.\ -""" - client = await self.get_client() - async with client: - response = await client.post('/chats', params=param_query) - response.raise_for_status() - return response.json() - - -async def get_chat(self, id, param_query=None): - """Информация о беседе или канале - -Получения информации о беседе или канале. -Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. -""" - client = await self.get_client() - async with client: - response = await client.get(f'/chats/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def post_members_to_chats(self, id, param_query=None): - """добавление пользователей в состав участников - -Метод для добавления пользователей в состав участников беседы или канала. -""" - client = await self.get_client() - async with client: - response = await client.post(f'/chats/{id}/members', params=param_query) - response.raise_for_status() - return response.json() - - -async def post_tags_to_chats(self, id, param_query=None): - """добавление тегов в состав участников беседы или канала - -Метод для добавления тегов в состав участников беседы или канала. -""" - client = await self.get_client() - async with client: - response = await client.post(f'/chats/{id}/group_tags', params=param_query) - response.raise_for_status() - return response.json() - - -async def leave_chat(self, id, param_query=None): - """Выход из беседы или канала - -Метод для самостоятельного выхода из беседы или канала.""" - client = await self.get_client() - async with client: - response = await client.delete(f'/chats/{id}/leave', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_thread(self, id, param_query=None): - """Создание нового треда - -Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. -""" - client = await self.get_client() - async with client: - response = await client.post(f'/messages/{id}/thread', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_message(self, param_query=None): - """создание нового сообщения - -Метод для отправки сообщения в беседу или канал, -личного сообщения пользователю или комментария в тред. - -При использовании entity_type: "discussion" (или просто без указания entity_type) -допускается отправка любого chat_id в поле entity_id. -То есть, сообщение можно отправить зная только идентификатор чата. -При этом, вы имеете возможность отправить сообщение в тред по его идентификатору -или личное сообщение по идентификатору пользователя. - -Для отправки личного сообщения пользователю создавать чат не требуется. -Достаточно указать entity_type: "user" и идентификатор пользователя. -Чат будет создан автоматически, если между вами ещё не было переписки. -Между двумя пользователями может быть только один личный чат. -""" - client = await self.get_client() - async with client: - response = await client.post('/messages', params=param_query) - response.raise_for_status() - return response.json() - - -async def edit_message(self, id, param_query=None): - """Редактирование сообщения - -Метод для редактирования сообщения или комментария.""" - client = await self.get_client() - async with client: - response = await client.put(f'/messages/{id}', params=param_query) - response.raise_for_status() - return response.json() - - -async def delete_message_reactions(self, id, param_query=None): - """Удаление реакции - -Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. -""" - client = await self.get_client() - async with client: - response = await client.delete(f'/messages/{id}/reactions', params=param_query) - response.raise_for_status() - return response.json() - - -async def create_task(self, param_query=None): - """Метод для создания нового напоминания. - -При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. -При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. -Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. -У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. -""" - client = await self.get_client() - async with client: - response = await client.post('/tasks', params=param_query) - response.raise_for_status() - return response.json() - diff --git a/src/generator2/bot.py b/src/generator2/bot.py new file mode 100644 index 0000000..48f5c7b --- /dev/null +++ b/src/generator2/bot.py @@ -0,0 +1,59 @@ +import inspect +import httpx +import importlib + +from request_methods_gen import get_obj_openapi_spec + + +TOKEN = 'Bearer -jJB_ARcOBS-c_3q1vu066uU6-bCEkMz23RCu9GEBJ8' + + +class RequestMethodsCollector(type): + + def __new__(cls, name, bases, dct): + req_methods = importlib.import_module('request_methods') + request_methods = cls.collect_methods(req_methods) + + for name_method, method in request_methods.items(): + dct[name_method] = method + + return super( + RequestMethodsCollector, cls + ).__new__(cls, name, bases, dct) + + @staticmethod + def collect_methods(module) -> dict[str, object]: + """Собирает генерируемые функции из модуля request_methods.py""" + dict_func = {} + + for name, obj in inspect.getmembers(module): + if inspect.isfunction(obj): + dict_func[name] = obj + + if not dict_func: + raise ValueError( + f"В модуле {module.__name__} " + "отсутствуют сгенерированные функции" + ) + + return dict_func + + +class PachcaBot(metaclass=RequestMethodsCollector): + base_url = get_obj_openapi_spec().servers[0].url + + def __init__(self, token): + self.token = token + + async def get_client(self): + return httpx.AsyncClient( + base_url=self.base_url, + headers={'Authorization': self.token}, + ) + + def format_url( + self, + url_template: str, + path_param: dict[str, int] = None + ): + return url_template.format(**path_param) diff --git a/src/generator2/gen_class_pachca.py b/src/generator2/gen_class_pachca.py deleted file mode 100644 index 56bf4d2..0000000 --- a/src/generator2/gen_class_pachca.py +++ /dev/null @@ -1,140 +0,0 @@ -import inspect -import re -from typing import Union - -import httpx -from openapi_parser import parse -from openapi_parser.specification import Path, Schema, Server, Specification - -import api_methods - -TOKEN = 'Bearer ' - - -async def get_client(self): - """Клиент генерируемого класса""" - return httpx.AsyncClient( - base_url=self.base_url, - headers={'Authorization': TOKEN} - ) - - -def get_obj_openapi_spec( - path_to_file='./src/generator2/openapi.yaml' -) -> Specification: - """Читает спецификацию openapi из файла openapi.yaml и возвращает - спецификацию в виде объекта Specification библиотеки openapi_parser""" - with open(path_to_file, 'r', encoding='utf-8') as file: - spec_openapi = file.read() - - return parse(spec_string=spec_openapi) - - -def collecting_class_properites(module) -> dict[str, Union[object, str]]: - """Собирает генерируемые функции из модуля api_methods.py - добавляет свойства класса и статичные функции.""" - dict_func = {} - - for name, obj in inspect.getmembers(module): - if inspect.isfunction(obj): - dict_func[name] = obj - - dict_func['get_client'] = get_client - - return dict_func - - -def gen_template(paths: Path) -> list[str]: - """Собирает параметры запроса всех paths спецификации - Возвращает список шаблонов функций""" - functions = [] - - for path in paths: - url = path.url - for operation in path.operations: - method_request = operation.method.value.lower() - function_name = '_'.join( - re.findall(r'[a-z]+|[A-Z][^A-Z]*', operation.operation_id) - ).lower() - docstring = (f'"""{operation.summary}\n' - f'\n{operation.description}"""') # Создать функцию для редактирования docstring - param_path = None - param_query = {} - # print(operation.parameters) - for param in operation.parameters: - if param.location.value == 'path': - param_path = param.name - if param.location.value == 'query': - param_query[param.name] = param.schema.default if param.schema.default else None - - # print(url) - functions.append( - get_template_methods( - function_name, - url, - method_request, - param_path, - param_query, - docstring - ) - ) - - return functions - - -def get_template_methods( - name_func, - url, - method_request, - param_path, - param_query, - docstring -): - """Возвращает шаблон генерируемой функции. - Вызывается в функции gen_template""" - if param_path: - function_declaration = (f"async def {name_func}" - f"(self, {param_path}, param_query=None):") - response = (f"response = await client.{method_request}" - f"(f'{url}', params=param_query)") - else: - function_declaration = f"async def {name_func}(self, param_query=None):" - response = (f"response = await client.{method_request}" - f"('{url}', params=param_query)") - return f""" -{function_declaration} - {docstring} - client = await self.get_client() - async with client: - {response} - response.raise_for_status() - return response.json() - -""" - - -spec: Specification = get_obj_openapi_spec() -servers: list[Server] = spec.servers -paths: list[Path] = spec.paths -schemas: dict[str, Schema] = spec.schemas -base_url = base_url = servers[0].url - -dict_properties_class = collecting_class_properites(api_methods) - -dict_properties_class['get_client'] = get_client # Добавляем метод get_client - -dict_properties_class['base_url'] = base_url # Добавляем свойство класса base_url - -PachcaBot: object = type('PachcaBot', (object,), dict_properties_class) - - -if __name__ == "__main__": - - templates = gen_template(paths) - - with open( - './src/generator2/api_methods.py', 'w', encoding='utf-8' - ) as file: - file.write('"""Сгенерированные методы запроса."""\n\n') - for template in templates: - file.write(template) diff --git a/src/generator2/openapi.yaml b/src/generator2/openapi.yaml index bb80f7b..59df7ac 100644 --- a/src/generator2/openapi.yaml +++ b/src/generator2/openapi.yaml @@ -452,7 +452,7 @@ paths: summary: Новая беседа или канал description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -1716,6 +1716,7 @@ components: direct_url: type: string DirectResponse: + title: DirectResponse type: object properties: Content-Disposition: diff --git a/src/generator2/pachca.py b/src/generator2/pachca.py index 4c80c49..00ba0a4 100644 --- a/src/generator2/pachca.py +++ b/src/generator2/pachca.py @@ -1,24 +1,24 @@ import asyncio -from gen_class_pachca import PachcaBot +from bot import PachcaBot, TOKEN if __name__ == '__main__': print(id(PachcaBot)) + print(PachcaBot) + pachca = PachcaBot(token=TOKEN) - pachca = PachcaBot() - - print(hasattr(pachca, 'client')) - - #print(hasattr(pachca, 'get_custom_properties')) + print(hasattr(pachca, 'get_common_methods')) async def run_pachca(): print(await pachca.get_employee(id=514505)) - print(await pachca.get_employees(param_query={'per': 1})) + print(await pachca.get_employees()) print(await pachca.get_tags()) print(await pachca.get_tags_employees(id=27470)) - print(await pachca.get_common_methods()) #Возвращает ошибку, нужно прописать обработку если (parameters.query и parameters.required) + #print(await pachca.get_common_methods()) #Возвращает ошибку, нужно прописать обработку если (parameters.query и parameters.required) asyncio.run(run_pachca()) print(type(pachca)) - print(pachca.__class__.__name__) \ No newline at end of file + print(pachca.__class__) + print(pachca.__class__.__class__) + print(pachca.__class__.__class__.__class__) diff --git a/src/generator2/request_methods.py b/src/generator2/request_methods.py new file mode 100644 index 0000000..3ca45a8 --- /dev/null +++ b/src/generator2/request_methods.py @@ -0,0 +1,250 @@ +"""Сгенерированные методы запроса.""" + + + +async def get_common_methods(self, entity_type: str = None): + """Список дополнительных полей + +Метод для получения актуального списка дополнительных полей участников и +напоминаний в вашей компании.""" + client = await self.get_client() + async with client: + url = '/custom_properties' + response = await client.get(url, params={ 'entity_type': entity_type }) + response.raise_for_status() + return response.json() + + +async def get_uploads(self): + """Получение подписи и ключа для загрузки файла + +Возвращает параметры, необходимые для безопасной загрузки файла.""" + client = await self.get_client() + async with client: + url = '/uploads' + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def get_direct_url(self): + """Получение URL для загрузки + +Отправляет запрос для получения URL для безопасной загрузки файла.""" + client = await self.get_client() + async with client: + url = '/direct_url' + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def get_employees(self, per: int = None, page: int = None, query: str = None): + """получение актуального списка всех сотрудников компании + +Fetch a paginated list of employees with optional filtering by query.""" + client = await self.get_client() + async with client: + url = '/users' + response = await client.get(url, params={ 'per': per, 'page': page, 'query': query }) + response.raise_for_status() + return response.json() + + +async def get_employee(self, id: int): + """получение информации о сотруднике + +Метод для получения информации о сотруднике. Для получения сотрудника вам +необходимо знать его id и указать его в URL запроса.""" + client = await self.get_client() + async with client: + url = self.format_url('/users/{id}', {'id': id}) + response = await client.get(url) + response.raise_for_status() + return response.json() + + +async def del_status(self): + """удаление своего статуса + +Параметры запроса отсутствуют""" + client = await self.get_client() + async with client: + url = '/profile/status' + response = await client.delete(url) + response.raise_for_status() + return response.json() + + +async def get_tag(self, id: int): + """Информация о теге + +Параметры запроса отсутствуют""" + client = await self.get_client() + async with client: + url = self.format_url('/group_tags/{id}', {'id': id}) + response = await client.get(url) + response.raise_for_status() + return response.json() + + +async def get_tags(self, per: int = None, page: int = None): + """Список тегов сотрудников + +Метод для получения актуального списка тегов сотрудников.""" + client = await self.get_client() + async with client: + url = '/group_tags' + response = await client.get(url, params={ 'per': per, 'page': page }) + response.raise_for_status() + return response.json() + + +async def get_tags_employees(self, id: int, per: int = None, page: int = None): + """получение актуального списка сотрудников тега + +Метод для получения актуального списка сотрудников тега.""" + client = await self.get_client() + async with client: + url = self.format_url('/group_tags/{id}/users', {'id': id}) + response = await client.get(url, params={ 'per': per, 'page': page }) + response.raise_for_status() + return response.json() + + +async def create_chat(self): + """Новая беседа или канал + +Метод для создания новой беседы или нового канала. При создании беседы или +канала вы автоматически становитесь участником.""" + client = await self.get_client() + async with client: + url = '/chats' + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def get_chat(self, id: int): + """Информация о беседе или канале + +Получения информации о беседе или канале. Для получения беседы или канала вам +необходимо знать её id и указать его в URL запроса.""" + client = await self.get_client() + async with client: + url = self.format_url('/chats/{id}', {'id': id}) + response = await client.get(url) + response.raise_for_status() + return response.json() + + +async def post_members_to_chats(self, id: int): + """добавление пользователей в состав участников + +Метод для добавления пользователей в состав участников беседы или канала.""" + client = await self.get_client() + async with client: + url = self.format_url('/chats/{id}/members', {'id': id}) + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def post_tags_to_chats(self, id: int): + """добавление тегов в состав участников беседы или канала + +Метод для добавления тегов в состав участников беседы или канала.""" + client = await self.get_client() + async with client: + url = self.format_url('/chats/{id}/group_tags', {'id': id}) + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def leave_chat(self, id: int): + """Выход из беседы или канала + +Метод для самостоятельного выхода из беседы или канала.""" + client = await self.get_client() + async with client: + url = self.format_url('/chats/{id}/leave', {'id': id}) + response = await client.delete(url) + response.raise_for_status() + return response.json() + + +async def create_thread(self, id: int): + """Создание нового треда + +Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был +создан тред, то в ответе вернётся информация об уже созданном ранее треде.""" + client = await self.get_client() + async with client: + url = self.format_url('/messages/{id}/thread', {'id': id}) + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def create_message(self): + """создание нового сообщения + +Метод для отправки сообщения в беседу или канал, личного сообщения пользователю +или комментария в тред. При использовании entity_type: "discussion" (или +просто без указания entity_type) допускается отправка любого chat_id в поле +entity_id. То есть, сообщение можно отправить зная только идентификатор чата. +При этом, вы имеете возможность отправить сообщение в тред по его +идентификатору или личное сообщение по идентификатору пользователя. Для +отправки личного сообщения пользователю создавать чат не требуется. Достаточно +указать entity_type: "user" и идентификатор пользователя. Чат будет создан +автоматически, если между вами ещё не было переписки. Между двумя +пользователями может быть только один личный чат.""" + client = await self.get_client() + async with client: + url = '/messages' + response = await client.post(url) + response.raise_for_status() + return response.json() + + +async def edit_message(self, id: int): + """Редактирование сообщения + +Метод для редактирования сообщения или комментария.""" + client = await self.get_client() + async with client: + url = self.format_url('/messages/{id}', {'id': id}) + response = await client.put(url) + response.raise_for_status() + return response.json() + + +async def delete_message_reactions(self, id: int, code: str = None): + """Удаление реакции + +Метод для удаления реакции на сообщение. Удалить можно только те реакции, +которые были поставлены авторизованным пользователем.""" + client = await self.get_client() + async with client: + url = self.format_url('/messages/{id}/reactions', {'id': id}) + response = await client.delete(url, params={ 'code': code }) + response.raise_for_status() + return response.json() + + +async def create_task(self): + """Метод для создания нового напоминания. + +При создании напоминания обязательным условием является указания типа +напоминания: звонок, встреча, простое напоминание, событие или письмо. При +этом не требуется дополнительное описание - вы просто создадите напоминание с +соответствующим текстом. Если вы укажите описание напоминания - то именно оно и +станет текстом напоминания. У напоминания должны быть ответственные, если их не +указывать - ответственным назначаетесь вы.""" + client = await self.get_client() + async with client: + url = '/tasks' + response = await client.post(url) + response.raise_for_status() + return response.json() diff --git a/src/generator2/request_methods_gen.py b/src/generator2/request_methods_gen.py new file mode 100644 index 0000000..59ae3fe --- /dev/null +++ b/src/generator2/request_methods_gen.py @@ -0,0 +1,162 @@ +import re +import os +import textwrap + +from openapi_parser import parse +from openapi_parser.specification import Path, Specification, DataType + + +def get_obj_openapi_spec( + path_to_file='openapi.yaml' +) -> Specification: + """Читает спецификацию openapi из файла openapi.yaml и возвращает + спецификацию в виде объекта Specification библиотеки openapi_parser""" + base_dir = os.path.dirname(os.path.abspath(__file__)) + full_path = os.path.join(base_dir, path_to_file) + + with open(full_path, 'r', encoding='utf-8') as file: + spec_openapi = file.read() + + return parse(spec_string=spec_openapi) + + +def get_template_methods( + name_func, + url, + method_request, + param_path: dict, + param_query: dict, + docstring +): + """Возвращает шаблон генерируемой функции. + Вызывается в функции gen_template""" + function_params = [] + if param_path: + for name, type_param in param_path.items(): + function_params.append(f'{name}: {type_param}') + if param_query: + for name, type_param in param_query.items(): + function_params.append(f'{name}: {type_param} = None') + function_params = ", ".join(["self"] + function_params) + + format_url = ( + f"url = self.format_url('{url}', {{" + + ", ".join([f"'{name}': {name}" for name in param_path]) + + "})" + if param_path else f"url = '{url}'" + ) + + get_response = ( + f"response = await client.{method_request}(url" + + (f", params={param_query}" if param_query else "") + + ")" + ) + + if param_query: + query_params = ", ".join([ + f"'{name}': {name}" for name in param_query.keys() + ]) + get_response = f"response = await client.{method_request}(url, params={{ {query_params} }})" + else: + get_response = f"response = await client.{method_request}(url)" + + return f""" + +async def {name_func}({function_params}): + {docstring} + client = await self.get_client() + async with client: + {format_url} + {get_response} + response.raise_for_status() + return response.json() +""" + + +def format_docstring(summary: str, description: str, max_width: int = 79): + """Редактирует длины строк докстринг + генерируемых функций в соответствиие с PEP8""" + formatted_summary = "\n".join(textwrap.wrap(summary, width=max_width)) + formatted_description = "\n".join( + textwrap.wrap(description, width=max_width) + ) + return f'"""{formatted_summary}\n\n{formatted_description}"""' + + +def format_name_func(operation_id: str): + "Возвращает название генерируемой функции запроса в требуемом формате" + return '_'.join( + re.findall(r'[a-z]+|[A-Z][^A-Z]*', operation_id) + ).lower() + + +def get_python_type(schema_type: DataType): + """Сопоставляет текущий тип данных параметра с типом данных Python + и возвращает его""" + type_mapping = { + DataType.STRING: "str", + DataType.INTEGER: "int", + DataType.NUMBER: "float", + DataType.BOOLEAN: "bool", + DataType.ARRAY: "list", + DataType.OBJECT: "dict", + } + + return type_mapping.get(schema_type, None) + + +def gen_template(paths: Path) -> list[str]: + """Собирает параметры запроса всех paths спецификации + Возвращает список шаблонов функций""" + functions = [] + + for path in paths: + url = path.url + for operation in path.operations: + method_request = operation.method.value.lower() + function_name = format_name_func(operation.operation_id) + docstring = format_docstring( + operation.summary, operation.description + ) + param_path = {} + param_query = {} + #for obj in operation.request_body.content: + # print(obj.schema.title) + #print(operation.request_body.content) + for param in operation.parameters: + if param.location.value == 'path': + schema_type = get_python_type(param.schema.type) + print(schema_type) + param_path[param.name] = schema_type + if param.location.value == 'query': + schema_type = get_python_type(param.schema.type) + param_query[param.name] = schema_type + + # print(url) + functions.append( + get_template_methods( + function_name, + url, + method_request, + param_path, + param_query, + docstring + ) + ) + + return functions + + +if __name__ == "__main__": + + spec: Specification = get_obj_openapi_spec() + paths: list[Path] = spec.paths + + templates = gen_template(paths) + + with open( + 'src/generator2/request_methods.py', 'w', encoding='utf-8' + ) as file: + file.write('"""Сгенерированные методы запроса."""\n\n') + for template in templates: + file.write(template) From aa1fcc8d4e9d94542e03278264a5794b4a9de042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Fri, 3 Jan 2025 00:24:37 +0300 Subject: [PATCH 138/296] code refactoring --- src/generator2/bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generator2/bot.py b/src/generator2/bot.py index 48f5c7b..8d2b57b 100644 --- a/src/generator2/bot.py +++ b/src/generator2/bot.py @@ -5,7 +5,7 @@ from request_methods_gen import get_obj_openapi_spec -TOKEN = 'Bearer -jJB_ARcOBS-c_3q1vu066uU6-bCEkMz23RCu9GEBJ8' +TOKEN = 'Bearer ' class RequestMethodsCollector(type): From 7ace088257c4dfc1b26de6427bb18a4ec5dd5e72 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 3 Jan 2025 15:37:03 +0300 Subject: [PATCH 139/296] more workarounds to generate responses for endpoints --- src/generator2/generate_pydantic_model.py | 17 +++++++- src/generator2/openapi_test.yaml | 2 +- src/generator2/schema_link_processor.py | 53 +++++++++++++++++++++++ src/generator2/yaml_processor.py | 38 +++++++++++++--- 4 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 3c3d4d7..c57cd84 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -1,5 +1,6 @@ from constants import ENUM_TYPES, PYTHON_TYPES from schema_link_processor import ( + load_schema, new_replace_ref_with_schema, ) @@ -41,7 +42,7 @@ def look_into_schema_new(schema: dict): upper_schema_name = list(schema.keys())[0] inner_schema = ( schema.get(upper_schema_name).get('properties') - or schema.get(upper_schema_name).get('items',{}).get('properties') + or schema.get(upper_schema_name).get('items', {}).get('properties') or schema.get(upper_schema_name).get('items',{}).get('items', {}).get('properties')) required_properties = schema.get(upper_schema_name).get('required', []) for property in inner_schema: @@ -51,11 +52,18 @@ def look_into_schema_new(schema: dict): (property, inner_body.get('type'), inner_body['enum']), ) inner_schema[property] = inner_body + + if inner_body.get('items', {}).get('$ref'): + inner_schema[property] = load_schema(inner_body.get('items', {}).get('$ref')) description = inner_body.get('description', 'No docstring provided') property_type = ( PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) if property_type is None: - property_type = [item.get('type') for item in inner_body.get('allOf') if '$ref' not in item][0] + property_type = ( + [item.get('type') for item + in inner_body.get('allOf') + if '$ref' not in item][0] + ) if 'enum' in inner_body: property_type = f'enum_{property}' if property_type == 'object': @@ -63,6 +71,8 @@ def look_into_schema_new(schema: dict): if property_type == 'array': list_type = inner_body.get("items").get("type") list_type = PYTHON_TYPES.get(list_type, list_type) + if list_type is None: + list_type = next(iter(inner_schema.keys())).capitalize() if list_type == 'object' or list_type == 'array': list_type = property.capitalize() if inner_body.get("items").get("items"): @@ -78,10 +88,13 @@ def look_into_schema_new(schema: dict): ) if ('allOf' in inner_body or inner_body.get('type') == 'object' + and inner_body.get('properties') or inner_body.get('type') == 'array' and inner_body.get('items', {}).get('properties') + or inner_body.get('items', {}).get('$ref') or inner_body.get('items', {}).get('items')): nested_properties.append(property) + for nested in nested_properties: nested_obj = new_replace_ref_with_schema(inner_schema) if nested in nested_obj: diff --git a/src/generator2/openapi_test.yaml b/src/generator2/openapi_test.yaml index 87dd396..c616c9f 100644 --- a/src/generator2/openapi_test.yaml +++ b/src/generator2/openapi_test.yaml @@ -1526,7 +1526,7 @@ paths: type: object properties: task: - $ref: '#/components/schemas/BaseTask' + $ref: '#/components/schemas/Task' responses: '201': description: Напоминание успешно создано diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index fd245ca..1d09eab 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -117,3 +117,56 @@ def simple_replace_ref_with_schema(schema: dict) -> dict: return schema schema[key] = load_schema(schema[key].get('$ref')) return schema + + +def replace_refs_with_schemas(data): + """ + Recursively walk through a dictionary and replace any value that is a dict with + the structure {'$ref': 'string'} with the result of load_schema(value['$ref']). + Additionally, for 'items' or 'properties' keys, process 'allOf' or single '$ref' when present. + + :param data: The dictionary to process. + :param load_schema: A function that takes a reference string and returns the corresponding schema. + :param unite_schemas: A function that takes a list of schemas from '$ref' and another object to unite them. + :return: The processed dictionary with all necessary replacements. + """ + if isinstance(data, dict): + for key, value in list(data.items()): # Use list to avoid runtime changes during iteration + if isinstance(value, dict): + if '$ref' in value and len(value) == 1: + # Replace the {'$ref': 'string'} structure with the loaded schema + ref_value = value['$ref'] + data[key] = load_schema(ref_value) + elif key in ['items', 'properties'] and isinstance(data[key], dict): + # Process 'allOf' or '$ref' when present + resolved_value = data[key] + if 'allOf' in resolved_value: + all_of = resolved_value['allOf'] + if isinstance(all_of, list): + ref_schemas = [load_schema(ref['$ref']) for ref in all_of if '$ref' in ref] + other_schemas = [obj for obj in all_of if not '$ref' in obj] + if other_schemas: + united_schema = unite_schemas(ref_schemas, other_schemas[0]) + data[key] = united_schema + else: + data[key] = unite_schemas(ref_schemas, {}) + elif '$ref' in resolved_value and len(resolved_value) == 1: + # Process a single $ref in items or properties + ref_value = resolved_value['$ref'] + data[key] = load_schema(ref_value) + else: + # Recursively process nested dictionaries + data[key] = replace_refs_with_schemas(resolved_value) + else: + # Recursively process nested dictionaries + data[key] = replace_refs_with_schemas(value) + elif isinstance(data, list): + for i, item in enumerate(data): + # Recursively process items in lists + data[i] = replace_refs_with_schemas(item) + return data + + +if __name__ == '__main__': + d = {'ResponseEditmessagePut200': {'type': 'object', 'properties': {'data': {'type': 'array', 'description': 'Созданное сообщение', 'items': {'$ref': '#/components/schemas/Message'}}}}} + print(replace_refs_with_schemas(d)) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 4229ca7..bd0798c 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -13,16 +13,16 @@ def get_all_endpoints(yaml_dict: dict): method_body = body.get(method_name) if method_body: method[method_name] = method_body - for body in method.values(): - yield path, body + for name, body in method.items(): + yield path, name, body method.clear() def process_endpoints() -> tuple[list, list]: """Обрабатывает эндпоинты.""" body: dict - for endpoint, body in get_all_endpoints(YAML_DICT): - print(endpoint) + for endpoint, method, body in get_all_endpoints(YAML_DICT): + print(endpoint, method) operation_id = body.get('operationId') print(operation_id) @@ -56,7 +56,7 @@ def process_endpoints() -> tuple[list, list]: request_body.get('content').get('application/json') or request_body.get('content').get('multipart/form-data')) if not schema: - break + continue schema_has_link = schema.get('schema').get('$ref', False) schema = ( {operation_id.capitalize(): load_schema(schema_has_link)} @@ -64,8 +64,34 @@ def process_endpoints() -> tuple[list, list]: else {operation_id.capitalize(): schema.get('schema')} ) look_into_schema_new(schema) - + print('\nRequestBodyEnd+++++++++++++++++++++++++++++++++++++++++++++\nResponses start\n') + try: + responses = body.get('responses', False) + if responses: + for code, response in responses.items(): + if 'content' not in response: + continue + schema = ( + response.get('content').get('application/json') + or response.get('content').get('multipart/form-data')) + if not schema: + continue + schema_has_link = schema.get('schema').get('$ref', False) + model_name = ( + f'Response{operation_id.capitalize()}' + f'{method.capitalize()}{code}') + schema = ( + {model_name: load_schema(schema_has_link)} + if schema_has_link + else {model_name: schema.get('schema')} + ) + look_into_schema_new(schema) + except Exception as e: + print(f'Unable to create responses for {operation_id, method, code}!!!') + print(e) print('='*80) + if operation_id == 'editMessage': + break return path_parameters, query_parameters From 6cd9e280532be661af5ae68d9ad4c8e7225b666b Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 3 Jan 2025 15:42:24 +0300 Subject: [PATCH 140/296] remove unused method --- src/generator2/schema_link_processor.py | 53 ------------------------- 1 file changed, 53 deletions(-) diff --git a/src/generator2/schema_link_processor.py b/src/generator2/schema_link_processor.py index 1d09eab..fd245ca 100644 --- a/src/generator2/schema_link_processor.py +++ b/src/generator2/schema_link_processor.py @@ -117,56 +117,3 @@ def simple_replace_ref_with_schema(schema: dict) -> dict: return schema schema[key] = load_schema(schema[key].get('$ref')) return schema - - -def replace_refs_with_schemas(data): - """ - Recursively walk through a dictionary and replace any value that is a dict with - the structure {'$ref': 'string'} with the result of load_schema(value['$ref']). - Additionally, for 'items' or 'properties' keys, process 'allOf' or single '$ref' when present. - - :param data: The dictionary to process. - :param load_schema: A function that takes a reference string and returns the corresponding schema. - :param unite_schemas: A function that takes a list of schemas from '$ref' and another object to unite them. - :return: The processed dictionary with all necessary replacements. - """ - if isinstance(data, dict): - for key, value in list(data.items()): # Use list to avoid runtime changes during iteration - if isinstance(value, dict): - if '$ref' in value and len(value) == 1: - # Replace the {'$ref': 'string'} structure with the loaded schema - ref_value = value['$ref'] - data[key] = load_schema(ref_value) - elif key in ['items', 'properties'] and isinstance(data[key], dict): - # Process 'allOf' or '$ref' when present - resolved_value = data[key] - if 'allOf' in resolved_value: - all_of = resolved_value['allOf'] - if isinstance(all_of, list): - ref_schemas = [load_schema(ref['$ref']) for ref in all_of if '$ref' in ref] - other_schemas = [obj for obj in all_of if not '$ref' in obj] - if other_schemas: - united_schema = unite_schemas(ref_schemas, other_schemas[0]) - data[key] = united_schema - else: - data[key] = unite_schemas(ref_schemas, {}) - elif '$ref' in resolved_value and len(resolved_value) == 1: - # Process a single $ref in items or properties - ref_value = resolved_value['$ref'] - data[key] = load_schema(ref_value) - else: - # Recursively process nested dictionaries - data[key] = replace_refs_with_schemas(resolved_value) - else: - # Recursively process nested dictionaries - data[key] = replace_refs_with_schemas(value) - elif isinstance(data, list): - for i, item in enumerate(data): - # Recursively process items in lists - data[i] = replace_refs_with_schemas(item) - return data - - -if __name__ == '__main__': - d = {'ResponseEditmessagePut200': {'type': 'object', 'properties': {'data': {'type': 'array', 'description': 'Созданное сообщение', 'items': {'$ref': '#/components/schemas/Message'}}}}} - print(replace_refs_with_schemas(d)) From 552cda0aa7367d8d66717e3194543b11c3e43ea2 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 3 Jan 2025 19:59:12 +0300 Subject: [PATCH 141/296] write all models to file ./models/all_models.py --- src/generator2/file_writer.py | 30 +++++++++++++++++++++++ src/generator2/generate_pydantic_model.py | 22 +++++++++++++---- src/generator2/yaml_processor.py | 17 ++++++++++--- 3 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 src/generator2/file_writer.py diff --git a/src/generator2/file_writer.py b/src/generator2/file_writer.py new file mode 100644 index 0000000..00e3199 --- /dev/null +++ b/src/generator2/file_writer.py @@ -0,0 +1,30 @@ +import errno +import os +import os.path +import pathlib + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + + +def safe_open_w(path): + ''' Open "path" for writing, creating any parent directories as needed. + ''' + mkdir_p(os.path.dirname(path)) + return open(path, 'a', encoding='utf-8') + + +def write_to_file(file_name: str, text_to_write: str): + with safe_open_w(pathlib.Path( + __file__).parent.resolve() / f'models/{file_name}.py' + ) as f: + f.write(text_to_write) + + +if __name__ == '__main__': + write_to_file('model_users.py', '\n\nANOTHER CODE HERE') diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index c57cd84..6276732 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -1,4 +1,5 @@ from constants import ENUM_TYPES, PYTHON_TYPES +from file_writer import write_to_file from schema_link_processor import ( load_schema, new_replace_ref_with_schema, @@ -103,9 +104,14 @@ def look_into_schema_new(schema: dict): ) else: look_into_schema_new(nested_obj) + # for enum_class in enum_properties: + # print(create_enum(*enum_class)) + # print(create_model(upper_schema_name, list_of_properties)) + result_code = '' for enum_class in enum_properties: - print(create_enum(*enum_class)) - print(create_model(upper_schema_name, list_of_properties)) + result_code += create_enum(*enum_class) + '\n\n' + result_code += create_model(upper_schema_name, list_of_properties) + '\n\n' + write_to_file('all_models', result_code) def look_into_schema(schema: dict) -> None: @@ -170,6 +176,12 @@ def look_into_schema(schema: dict) -> None: look_into_schema(new_replace_ref_with_schema( {nested.capitalize(): inner_schema.get(nested)}), ) - for enum_class in enum_properties: - print(create_enum(*enum_class)) - print(create_model(upper_schema_name, list_of_properties)) + + # for enum_class in enum_properties: + # print(create_enum(*enum_class)) + # print(create_model(upper_schema_name, list_of_properties)) + # result_code = '' + # for enum_class in enum_properties: + # result_code += create_enum(*enum_class) + # result_code += create_model(upper_schema_name, list_of_properties) + # write_to_file('all_models', result_code) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index bd0798c..4103605 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -1,4 +1,5 @@ from constants import HTTP_METHODS +from file_writer import write_to_file from generate_pydantic_model import look_into_schema_new from schema_link_processor import load_schema from yaml_loader import YAML_DICT @@ -19,7 +20,19 @@ def get_all_endpoints(yaml_dict: dict): def process_endpoints() -> tuple[list, list]: - """Обрабатывает эндпоинты.""" + """Обрабатывает эндпоинты. + + Проходит по каждому эндпоинту в openapi файле и генерирует модели для + каждой схемы в requestBody и resopnse. + """ + write_to_file( + 'all_models', + ( + 'from enum import Enum\n' + 'from typing import List, Optional\n' + 'from pydantic import BaseModel, Field\n\n\n' + ) + ) body: dict for endpoint, method, body in get_all_endpoints(YAML_DICT): print(endpoint, method) @@ -90,8 +103,6 @@ def process_endpoints() -> tuple[list, list]: print(f'Unable to create responses for {operation_id, method, code}!!!') print(e) print('='*80) - if operation_id == 'editMessage': - break return path_parameters, query_parameters From 8f268ca072b61bcb6d457bd25d34c935e3bd8dc1 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 3 Jan 2025 20:25:41 +0300 Subject: [PATCH 142/296] fixes in generated pydantic models --- src/generator2/generate_pydantic_model.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 6276732..71e124e 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -9,16 +9,24 @@ def create_model(name: str, fields: list) -> str: """Генерирует код модели Pydantic.""" model_code = f'class {name}(BaseModel):\n' + alias = '' for field in fields: + field_name = field[0] + if '-' in field[0]: + alias = f', alilas=\'{field[0]}\'' + field_name = field_name.replace('-', '_') + else: + alias = '' + if field[2]: model_code += ( - f' {field[0]}: {field[1]} ' - f'= Field(..., description=\'{field[3]}\')\n' + f' {field_name}: {field[1]} ' + f'= Field(..., description=\'{field[3]}\'{alias})\n' ) else: model_code += ( - f' {field[0]}: Optional[{field[1]}] ' - f'= Field(None, description=\'{field[3]}\')\n' + f' {field_name}: Optional[{field[1]}] ' + f'= Field(None, description=\'{field[3]}\'{alias})\n' ) return model_code @@ -84,7 +92,7 @@ def look_into_schema_new(schema: dict): property, property_type, True if property in required_properties else False, - description, + description.replace('\n', ''), ), ) if ('allOf' in inner_body From 98a37131d48241dd0a52d66c11d7e1e216beda20 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Fri, 3 Jan 2025 22:55:10 +0300 Subject: [PATCH 143/296] models generation into files --- src/generator2/file_writer.py | 6 + src/generator2/generate_pydantic_model.py | 154 ++++++++++------------ src/generator2/yaml_processor.py | 36 +++-- 3 files changed, 104 insertions(+), 92 deletions(-) diff --git a/src/generator2/file_writer.py b/src/generator2/file_writer.py index 00e3199..d010050 100644 --- a/src/generator2/file_writer.py +++ b/src/generator2/file_writer.py @@ -4,6 +4,9 @@ import pathlib +# presented_code = set() + + def mkdir_p(path): try: os.makedirs(path) @@ -24,6 +27,9 @@ def write_to_file(file_name: str, text_to_write: str): __file__).parent.resolve() / f'models/{file_name}.py' ) as f: f.write(text_to_write) + # if text_to_write not in presented_code: + # f.write(text_to_write) + # presented_code.add(text_to_write) if __name__ == '__main__': diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index 71e124e..2a14448 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -42,7 +42,7 @@ def create_enum(name: str, enum_type: str, fields: list): return enum_class_code -def look_into_schema_new(schema: dict): +def look_into_schema_new(schema: dict, file_name: str): schema = new_replace_ref_with_schema(schema) list_of_properties = [] nested_properties = [] @@ -61,7 +61,7 @@ def look_into_schema_new(schema: dict): (property, inner_body.get('type'), inner_body['enum']), ) inner_schema[property] = inner_body - + if inner_body.get('items', {}).get('$ref'): inner_schema[property] = load_schema(inner_body.get('items', {}).get('$ref')) description = inner_body.get('description', 'No docstring provided') @@ -87,6 +87,8 @@ def look_into_schema_new(schema: dict): if inner_body.get("items").get("items"): list_type = f'List[{list_type}]' property_type = (f'List[{list_type}]') + if property_type == 'Payload': + property_type = 'Dict' list_of_properties.append( ( property, @@ -108,88 +110,78 @@ def look_into_schema_new(schema: dict): nested_obj = new_replace_ref_with_schema(inner_schema) if nested in nested_obj: look_into_schema_new( - {nested.capitalize(): nested_obj[nested]} + {nested.capitalize(): nested_obj[nested]}, + file_name=file_name ) else: - look_into_schema_new(nested_obj) - # for enum_class in enum_properties: - # print(create_enum(*enum_class)) - # print(create_model(upper_schema_name, list_of_properties)) - result_code = '' - for enum_class in enum_properties: - result_code += create_enum(*enum_class) + '\n\n' - result_code += create_model(upper_schema_name, list_of_properties) + '\n\n' - write_to_file('all_models', result_code) + look_into_schema_new(nested_obj, file_name=file_name) + for enum_class in enum_properties: + write_to_file(file_name, create_enum(*enum_class) + '\n\n') + write_to_file( + file_name, + create_model(upper_schema_name, list_of_properties) + '\n\n') -def look_into_schema(schema: dict) -> None: - """Рекурсивно разбирает схемы. - Генерирует модели pydantic для requestBody. - """ - list_of_properties = [] - nested_properties = [] - enum_properties = [] - required_properties = [] - upper_schema_name = list(schema.keys())[0] - inner_schema = schema.get(upper_schema_name).get('properties') - required_properties = schema.get(upper_schema_name).get('required', []) - for property in inner_schema: - inner_body = new_replace_ref_with_schema(inner_schema.get(property)) - if 'enum' in inner_body: - enum_properties.append( - (property, inner_body.get('type'), inner_body['enum']), - ) - description = inner_body.get('description', 'No docstring provided') - property_type = ( - PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) - if 'enum' in inner_body: - property_type = f'enum_{property}' - if property_type == 'object': - property_type = property.capitalize() - if property_type == 'array': - list_type = inner_body.get("items").get("type") - list_type = PYTHON_TYPES.get(list_type, list_type) - if list_type == 'object' or list_type == 'array': - list_type = property.capitalize() - property_type = (f'List[{list_type}]') - list_of_properties.append( - ( - property, - property_type, - True if property in required_properties else False, - description, - ), - ) - if (inner_body.get('type') == 'object' - or inner_body.get('type') == 'array' - and inner_body.get('items', {}).get('properties') - or inner_body.get('items', {}).get('items')): - nested_properties.append(property) - for nested in nested_properties: - if ('items' in inner_schema.get(nested) - and inner_schema.get(nested).get('items').get('properties')): - look_into_schema(new_replace_ref_with_schema( - {nested.capitalize(): inner_schema.get(nested).get('items')}), - ) - elif ('items' in inner_schema.get(nested) - and inner_schema.get(nested).get('items').get('items')): - look_into_schema(new_replace_ref_with_schema( - { - nested.capitalize(): - inner_schema.get(nested).get('items').get('items'), - }), - ) - else: - look_into_schema(new_replace_ref_with_schema( - {nested.capitalize(): inner_schema.get(nested)}), - ) +# def look_into_schema(schema: dict) -> None: +# """Рекурсивно разбирает схемы. - # for enum_class in enum_properties: - # print(create_enum(*enum_class)) - # print(create_model(upper_schema_name, list_of_properties)) - # result_code = '' - # for enum_class in enum_properties: - # result_code += create_enum(*enum_class) - # result_code += create_model(upper_schema_name, list_of_properties) - # write_to_file('all_models', result_code) +# Генерирует модели pydantic для requestBody. +# """ +# list_of_properties = [] +# nested_properties = [] +# enum_properties = [] +# required_properties = [] +# upper_schema_name = list(schema.keys())[0] +# inner_schema = schema.get(upper_schema_name).get('properties') +# required_properties = schema.get(upper_schema_name).get('required', []) +# for property in inner_schema: +# inner_body = new_replace_ref_with_schema(inner_schema.get(property)) +# if 'enum' in inner_body: +# enum_properties.append( +# (property, inner_body.get('type'), inner_body['enum']), +# ) +# description = inner_body.get('description', 'No docstring provided') +# property_type = ( +# PYTHON_TYPES.get(inner_body.get('type')) or inner_body.get('type')) +# if 'enum' in inner_body: +# property_type = f'enum_{property}' +# if property_type == 'object': +# property_type = property.capitalize() +# if property_type == 'array': +# list_type = inner_body.get("items").get("type") +# list_type = PYTHON_TYPES.get(list_type, list_type) +# if list_type == 'object' or list_type == 'array': +# list_type = property.capitalize() +# property_type = (f'List[{list_type}]') +# list_of_properties.append( +# ( +# property, +# property_type, +# True if property in required_properties else False, +# description, +# ), +# ) +# if (inner_body.get('type') == 'object' +# or inner_body.get('type') == 'array' +# and inner_body.get('items', {}).get('properties') +# or inner_body.get('items', {}).get('items')): +# nested_properties.append(property) +# for nested in nested_properties: +# if ('items' in inner_schema.get(nested) +# and inner_schema.get(nested).get('items').get('properties')): +# look_into_schema(new_replace_ref_with_schema( +# {nested.capitalize(): inner_schema.get(nested).get('items')}), +# ) +# elif ('items' in inner_schema.get(nested) +# and inner_schema.get(nested).get('items').get('items')): +# look_into_schema(new_replace_ref_with_schema( +# { +# nested.capitalize(): +# inner_schema.get(nested).get('items').get('items'), +# }), +# ) +# else: +# look_into_schema(new_replace_ref_with_schema( +# {nested.capitalize(): inner_schema.get(nested)}), +# ) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 4103605..0f48b99 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -1,3 +1,4 @@ +import sys from constants import HTTP_METHODS from file_writer import write_to_file from generate_pydantic_model import look_into_schema_new @@ -25,19 +26,11 @@ def process_endpoints() -> tuple[list, list]: Проходит по каждому эндпоинту в openapi файле и генерирует модели для каждой схемы в requestBody и resopnse. """ - write_to_file( - 'all_models', - ( - 'from enum import Enum\n' - 'from typing import List, Optional\n' - 'from pydantic import BaseModel, Field\n\n\n' - ) - ) + body: dict for endpoint, method, body in get_all_endpoints(YAML_DICT): print(endpoint, method) operation_id = body.get('operationId') - print(operation_id) parameters = body.get('parameters') path_parameters = [] @@ -65,6 +58,15 @@ def process_endpoints() -> tuple[list, list]: print('query: ', query_parameters) request_body = body.get('requestBody') if request_body: + write_to_file( + f'models_reqBod_{operation_id}', + ( + 'from enum import Enum, IntEnum' + f'{"" if sys.version_info[1] < 11 else ", StrEnum"}\n' + 'from typing import Dict, Optional, List\n' + 'from pydantic import Field, BaseModel\n\n\n' + ) + ) schema = ( request_body.get('content').get('application/json') or request_body.get('content').get('multipart/form-data')) @@ -76,12 +78,21 @@ def process_endpoints() -> tuple[list, list]: if schema_has_link else {operation_id.capitalize(): schema.get('schema')} ) - look_into_schema_new(schema) + look_into_schema_new(schema, 'models_reqBod_' + operation_id) print('\nRequestBodyEnd+++++++++++++++++++++++++++++++++++++++++++++\nResponses start\n') try: responses = body.get('responses', False) if responses: for code, response in responses.items(): + write_to_file( + f'models_response_{operation_id}{method}{code}', + ( + 'from enum import Enum, IntEnum' + f'{"" if sys.version_info[1] < 11 else ", StrEnum"}\n' + 'from typing import Dict, Optional, List\n' + 'from pydantic import Field, BaseModel\n\n\n' + ) + ) if 'content' not in response: continue schema = ( @@ -98,7 +109,10 @@ def process_endpoints() -> tuple[list, list]: if schema_has_link else {model_name: schema.get('schema')} ) - look_into_schema_new(schema) + look_into_schema_new( + schema, + f'models_response_{operation_id}{method}{code}' + ) except Exception as e: print(f'Unable to create responses for {operation_id, method, code}!!!') print(e) From 9fcd34eb232f127e87cfdba76940e9fd98e82a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sat, 4 Jan 2025 19:11:40 +0300 Subject: [PATCH 144/296] imports fixes --- src/generator1/script.py | 94 +++++++++++++++++------- src/generator1/templates/client.py.jinja | 4 +- 2 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/generator1/script.py b/src/generator1/script.py index d8e20cf..4af47da 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -14,18 +14,20 @@ def extract_functions_and_imports_from_file(file_path) -> None: imports = [] for node in ast.walk(tree): - if isinstance(node, ast.AsyncFunctionDef) or isinstance(node, ast.FunctionDef): + if isinstance(node, ast.AsyncFunctionDef) or isinstance( + node, ast.FunctionDef + ): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): - module = node.module if node.module else '.' + module = node.module if node.module else "." for alias in node.names: - if module == 'typing': + if module == "typing": imports.append(f"from typing import {alias.name}") - elif module.startswith('models'): + elif module.startswith("models"): imports.append(f"from .models import {alias.name}") - elif module == 'types': + elif module == "types": imports.append(f"from .types import {alias.name}") - elif module == 'client_serv': + elif module == "client_serv": imports.append(f"from .client_serv import {alias.name}") else: imports.append(f"from {module} import {alias.name}") @@ -40,7 +42,9 @@ def get_all_api_functions_and_imports(api_dir): for file in files: if file.endswith(".py"): file_path = os.path.join(root, file) - functions, imports = extract_functions_and_imports_from_file(file_path) + functions, imports = extract_functions_and_imports_from_file( + file_path + ) all_functions.extend(functions) all_imports.extend(imports) return all_functions, all_imports @@ -49,7 +53,7 @@ def get_all_api_functions_and_imports(api_dir): def get_base_url_from_yaml(openapi_yaml): with open(openapi_yaml, "r", encoding="utf-8") as file: data = yaml.safe_load(file) - return data['servers'][0]['url'] + return data["servers"][0]["url"] api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" @@ -58,38 +62,74 @@ def get_base_url_from_yaml(openapi_yaml): base_url = get_base_url_from_yaml(openapi_yaml) env = Environment( - loader=FileSystemLoader('templates'), + loader=FileSystemLoader("templates"), ) -client_template = env.get_template('client.py.jinja') +client_template = env.get_template("client.py.jinja") -client_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' +client_path = ( + "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" +) -with open(client_path, mode='w', encoding="utf-8") as file: +with open(client_path, mode="w", encoding="utf-8") as file: unique_imports = list(set(imports)) - models_imports = sorted([model for model in unique_imports if model.startswith('from .models')]) - typing_imports = sorted([model for model in unique_imports if model.startswith('from typing import')]) - types_imports = sorted([model for model in unique_imports if model.startswith('from .types import')]) - other_imports = sorted(list( - set(unique_imports) - set(typing_imports) - set(types_imports) - set(models_imports))) + models_imports = sorted( + [model for model in unique_imports if model.startswith("from .models")] + ) + typing_imports = [ + model + for model in unique_imports + if model.startswith("from typing import") + ] + types_imports = sorted( + [ + model + for model in unique_imports + if model.startswith("from .types import") + ] + ) + other_imports = sorted( + list( + set(unique_imports) + - set(typing_imports) + - set(types_imports) + - set(models_imports) + ) + ) if models_imports: - models_imports_str = "from .models import (\n " + ",\n ".join( - [model.split('from .models import ')[-1] for model in models_imports]) + "\n)" + models_imports_str = ( + "from .models import (\n " + + ",\n ".join( + [ + model.split("from .models import ")[-1] + for model in models_imports + ] + ) + + "\n)" + ) file.write(models_imports_str + "\n\n") - if typing_imports: - typing_imports_str = "from typing import (\n " + ",\n ".join( - [model.split('from typing import ')[-1] for model in typing_imports]) + "\n)" - file.write(typing_imports_str + "\n\n") if types_imports: - types_imports_str = "from .types import (\n " + ",\n ".join( - [model.split('from .types import ')[-1] for model in types_imports]) + "\n)" + types_imports_str = ( + "from .types import (\n " + + ",\n ".join( + [ + model.split("from .types import ")[-1] + for model in types_imports + ] + ) + + "\n)" + ) file.write(types_imports_str + "\n\n") if other_imports: file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints, base_url=base_url)) # Копирование client_servis.py -cli_servis_path = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client_serv.py' +cli_servis_path = "./pachca-api-open-api-3-0-client/" \ + "pachca_api_open_api_3_0_client/" \ + "client_serv.py" # Определяем путь к файлу, который нужно скопировать -source_file = os.path.join(os.path.dirname(__file__), '..', 'generator1', 'client_servis.py') +source_file = os.path.join( + os.path.dirname(__file__), "..", "generator1", "client_servis.py" +) shutil.copy(source_file, cli_servis_path) diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index 8b1ef64..a65552d 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -1,7 +1,7 @@ import datetime import ssl -from typing import Any, Union, Optional +from typing import Any, Union, Optional, cast from attrs import define, field, evolve import httpx @@ -9,8 +9,6 @@ import httpx from .client_serv import HttpClient {% from "macros/client_macros.py.jinja" import httpx_args_docstring %} - - @define class AuthenticatedClient: """A Client which has been authenticated for use on secured endpoints From ebba1cfab3d40f47d1a1545074dfb81ddf6b350b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Sun, 5 Jan 2025 03:35:09 +0300 Subject: [PATCH 145/296] pep8 fixes --- src/generator1/pachca.py | 2 +- src/generator1/requirements.txt | 4 +- src/generator1/script.py | 58 ++++++++++++++++++------ src/generator1/templates/errors.py.jinja | 17 +++++++ 4 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 src/generator1/templates/errors.py.jinja diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index e1932a7..04e5fc6 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -20,7 +20,7 @@ async def main() -> None: - """ Функция теста эндпоинтов """ + """Функция теста эндпоинтов""" task1 = asyncio.create_task(pachca.createChat(body=chat_body)) task2 = asyncio.create_task(pachca.getEmployees()) diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index ed4d7aa..e41286c 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -7,4 +7,6 @@ openapi-python-client==0.22.0 PyYAML==6.0.2 ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 -typing_extensions==4.12.2 \ No newline at end of file +typing_extensions==4.12.2 +black==24.10.0 +isort==5.13.2 \ No newline at end of file diff --git a/src/generator1/script.py b/src/generator1/script.py index 4af47da..bbb3e49 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -1,6 +1,7 @@ import ast import os import shutil +import subprocess import yaml from jinja2 import Environment, FileSystemLoader @@ -15,7 +16,8 @@ def extract_functions_and_imports_from_file(file_path) -> None: for node in ast.walk(tree): if isinstance(node, ast.AsyncFunctionDef) or isinstance( - node, ast.FunctionDef + node, + ast.FunctionDef, ): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): @@ -43,7 +45,7 @@ def get_all_api_functions_and_imports(api_dir): if file.endswith(".py"): file_path = os.path.join(root, file) functions, imports = extract_functions_and_imports_from_file( - file_path + file_path, ) all_functions.extend(functions) all_imports.extend(imports) @@ -77,24 +79,24 @@ def get_base_url_from_yaml(openapi_yaml): [model for model in unique_imports if model.startswith("from .models")] ) typing_imports = [ - model - for model in unique_imports - if model.startswith("from typing import") - ] + model + for model in unique_imports + if model.startswith("from typing import") + ] types_imports = sorted( [ model for model in unique_imports if model.startswith("from .types import") - ] + ], ) other_imports = sorted( list( set(unique_imports) - set(typing_imports) - set(types_imports) - - set(models_imports) - ) + - set(models_imports), + ), ) if models_imports: models_imports_str = ( @@ -103,7 +105,7 @@ def get_base_url_from_yaml(openapi_yaml): [ model.split("from .models import ")[-1] for model in models_imports - ] + ], ) + "\n)" ) @@ -115,7 +117,7 @@ def get_base_url_from_yaml(openapi_yaml): [ model.split("from .types import ")[-1] for model in types_imports - ] + ], ) + "\n)" ) @@ -125,11 +127,37 @@ def get_base_url_from_yaml(openapi_yaml): file.write(client_template.render(endpoints=endpoints, base_url=base_url)) # Копирование client_servis.py -cli_servis_path = "./pachca-api-open-api-3-0-client/" \ - "pachca_api_open_api_3_0_client/" \ - "client_serv.py" +cli_servis_path = ( + "./pachca-api-open-api-3-0-client/" + "pachca_api_open_api_3_0_client/" + "client_serv.py" +) # Определяем путь к файлу, который нужно скопировать source_file = os.path.join( - os.path.dirname(__file__), "..", "generator1", "client_servis.py" + os.path.dirname(__file__), + "..", + "generator1", + "client_servis.py", ) shutil.copy(source_file, cli_servis_path) + +try: + subprocess.run( + [ + "black", + "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/" + "**/*.py", + "--line-length", + "79", + ], + check=True, + ) + subprocess.run( + [ + "isort", + "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/" + "*.py", + ] + ) +except subprocess.CalledProcessError as e: + print("Автолинтер не сработал!", e) diff --git a/src/generator1/templates/errors.py.jinja b/src/generator1/templates/errors.py.jinja new file mode 100644 index 0000000..4a2b798 --- /dev/null +++ b/src/generator1/templates/errors.py.jinja @@ -0,0 +1,17 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\n" + f"Response content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] \ No newline at end of file From 92b579f9808d1d0c53f4b454d437d570812d93b0 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 5 Jan 2025 11:31:56 +0300 Subject: [PATCH 146/296] fix generation of files without models --- src/generator2/yaml_processor.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 0f48b99..0d2584d 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -79,11 +79,18 @@ def process_endpoints() -> tuple[list, list]: else {operation_id.capitalize(): schema.get('schema')} ) look_into_schema_new(schema, 'models_reqBod_' + operation_id) - print('\nRequestBodyEnd+++++++++++++++++++++++++++++++++++++++++++++\nResponses start\n') + # print('\nRequestBodyEnd+++++++++++++++++++++++++++++++++++++++++++++\nResponses start\n') try: responses = body.get('responses', False) if responses: for code, response in responses.items(): + if 'content' not in response: + continue + schema = ( + response.get('content').get('application/json') + or response.get('content').get('multipart/form-data')) + if not schema: + continue write_to_file( f'models_response_{operation_id}{method}{code}', ( @@ -93,13 +100,6 @@ def process_endpoints() -> tuple[list, list]: 'from pydantic import Field, BaseModel\n\n\n' ) ) - if 'content' not in response: - continue - schema = ( - response.get('content').get('application/json') - or response.get('content').get('multipart/form-data')) - if not schema: - continue schema_has_link = schema.get('schema').get('$ref', False) model_name = ( f'Response{operation_id.capitalize()}' From 1619577798b4e2633a3d1f5b4e641305a820e9f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 5 Jan 2025 18:52:23 +0300 Subject: [PATCH 147/296] fix client_servis.py - AuthenticatedClient --- src/generator1/client_servis.py | 145 ++++++++++++++++-- src/generator1/pachca.py | 4 - src/generator1/script.py | 1 - src/generator1/templates/client.py.jinja | 84 +--------- .../templates/endpoint_module.py.jinja | 9 +- 5 files changed, 138 insertions(+), 105 deletions(-) diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index da87d93..fae0ea2 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -1,13 +1,134 @@ +import ssl +from typing import Any, Optional, Union + import httpx -from typing import Any - -class HttpClient: - @staticmethod - async def send_request(method: str, url: str, token: str, **kwargs: Any) -> httpx.Response: - headers = kwargs.get('headers', {}) - headers['Authorization'] = f"Bearer {token}" - kwargs['headers'] = headers - - async with httpx.AsyncClient() as client: - response = await client.request(method, url, **kwargs) - return response +from attrs import define, evolve, field + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(default="https://api.pachca.com/api/shared/v1", kw_only=True, alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index e1932a7..8c1f67a 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -1,7 +1,3 @@ -# pachca = Pachca( -# token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', -# base_url = 'https://api.pachca.com/api/shared/v1' -# ) import asyncio from pachca_api_open_api_3_0_client.client import Pachca diff --git a/src/generator1/script.py b/src/generator1/script.py index 476ecb5..d70e499 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -32,7 +32,6 @@ def extract_functions_and_imports_from_file(file_path) -> None: return functions, imports - def get_all_api_functions_and_imports(api_dir): all_functions = [] all_imports = [] diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index 8b1ef64..0508bb6 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -1,97 +1,19 @@ import datetime - import ssl from typing import Any, Union, Optional from attrs import define, field, evolve import httpx - -from .client_serv import HttpClient +from .client_serv import AuthenticatedClient {% from "macros/client_macros.py.jinja" import httpx_args_docstring %} -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - {{ httpx_args_docstring() }} - - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - base_url: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._async_client = httpx.AsyncClient( - base_url=self.base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - class Pachca: """Главный класс библиотеки.""" - def __init__(self, token, base_url='{{ base_url }}'): - self.client = AuthenticatedClient( - token=token, - base_url=base_url - ) + def __init__(self, token): + self.client = AuthenticatedClient(token=token) {% if endpoints %} {% for endpoint in endpoints %} diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index a786b13..5310e9e 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -3,11 +3,10 @@ from typing import Any, Optional, Union, cast import httpx -from ...client import AuthenticatedClient, Client from ...types import Response, UNSET from ... import errors +from .client_serv import AuthenticatedClient -from .client_serv import HttpClient {% for relative in endpoint.relative_imports | sort %} {{ relative }} {% endfor %} @@ -110,14 +109,10 @@ async def {{ endpoint.name }}(self, {{ kwargs(endpoint, include_client=False) }} ) - base_url = self.client.base_url # Получаем базовый URL из клиента - kwargs['url'] = f"{base_url}{kwargs['url']}" # Формируем полный URL - response = await HttpClient.send_request( - token=self.client.token, + response = await self.client.get_async_httpx_client().request( **kwargs ) return self._build_response_{{ endpoint.name }}( response=response).parsed {% endif %} - From 5df8f9d6484e8042695e727faddd9ed4c2dfb811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Sun, 5 Jan 2025 21:08:03 +0300 Subject: [PATCH 148/296] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=89=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=D1=8B=D1=85=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D0=B2,=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D0=B2?= =?UTF-8?q?=D0=B0=D0=B5=D0=BC=D1=8B=D1=85=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D0=B2,=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D0=B0,=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 12 + src/generator1/pachca.py | 3 +- src/generator1/script.py | 2 +- src/generator2/README.md | 4 +- src/generator2/bot.py | 25 +- src/generator2/openapi.yaml | 2205 +++++++++++++------------ src/generator2/pachca.py | 24 - src/generator2/request_methods.py | 250 --- src/generator2/request_methods_gen.py | 171 +- 9 files changed, 1320 insertions(+), 1376 deletions(-) delete mode 100644 src/generator2/pachca.py diff --git a/requirements.txt b/requirements.txt index a004395..a81d2e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,32 @@ +annotated-types==0.7.0 anyio==4.7.0 attrs==24.3.0 certifi==2024.12.14 +cfgv==3.4.0 chardet==5.2.0 charset-normalizer==3.4.1 +distlib==0.3.9 +filelock==3.16.1 h11==0.14.0 httpcore==1.0.7 httpx==0.28.1 +identify==2.6.4 idna==3.10 jsonschema==4.23.0 jsonschema-spec==0.2.4 jsonschema-specifications==2023.7.1 lazy-object-proxy==1.10.0 +nodeenv==1.9.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.6.0 openapi3-parser==1.1.19 packaging==24.2 pathable==0.4.3 +platformdirs==4.3.6 prance==23.6.21.0 +pre-commit==3.8.0 +pydantic==2.10.4 +pydantic_core==2.27.2 PyYAML==6.0.2 referencing==0.30.2 requests==2.32.3 @@ -24,7 +34,9 @@ rfc3339-validator==0.1.4 rpds-py==0.22.3 ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 +ruff==0.7.1 six==1.17.0 sniffio==1.3.1 typing_extensions==4.12.2 urllib3==2.3.0 +virtualenv==20.28.1 diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index bf5bef7..ab187dc 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -16,8 +16,7 @@ async def main() -> None: - """ Функция теста эндпоинтов """ - + """Функция теста эндпоинтов""" task1 = asyncio.create_task(pachca.createChat(body=chat_body)) task2 = asyncio.create_task(pachca.getEmployees()) diff --git a/src/generator1/script.py b/src/generator1/script.py index 5a140e3..0782cd9 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -46,7 +46,7 @@ def get_all_api_functions_and_imports(api_dir): endpoints, imports = get_all_api_functions_and_imports(api_dir) env = Environment( - loader=FileSystemLoader('templates') + loader=FileSystemLoader('templates'), ) client_template = env.get_template('client.py.jinja') diff --git a/src/generator2/README.md b/src/generator2/README.md index 8af04b9..a63268f 100644 --- a/src/generator2/README.md +++ b/src/generator2/README.md @@ -1 +1,3 @@ -Запустить файл gen_class_pachca.py. Код сгенерирует функции запросов в файле api_methods.py и объявит класс PachcaBot, присвоит ему созданные функции и функцию клиента. Файл pachca.py создан для демонстрации. \ No newline at end of file +Развернуть venv в корне директории +Установить зависимости из requirements.txt +Запустить выполнение файла request_methods_gen.py. В файл request_methods.py будут записаны методы запроса для класса PachcaBot из файла bot.py \ No newline at end of file diff --git a/src/generator2/bot.py b/src/generator2/bot.py index 8d2b57b..143658d 100644 --- a/src/generator2/bot.py +++ b/src/generator2/bot.py @@ -1,13 +1,10 @@ -import inspect -import httpx import importlib +import inspect +import httpx from request_methods_gen import get_obj_openapi_spec -TOKEN = 'Bearer ' - - class RequestMethodsCollector(type): def __new__(cls, name, bases, dct): @@ -18,12 +15,12 @@ def __new__(cls, name, bases, dct): dct[name_method] = method return super( - RequestMethodsCollector, cls + RequestMethodsCollector, cls, ).__new__(cls, name, bases, dct) @staticmethod def collect_methods(module) -> dict[str, object]: - """Собирает генерируемые функции из модуля request_methods.py""" + """Собирает сгенерированные функции из модуля request_methods.py""" dict_func = {} for name, obj in inspect.getmembers(module): @@ -33,7 +30,7 @@ def collect_methods(module) -> dict[str, object]: if not dict_func: raise ValueError( f"В модуле {module.__name__} " - "отсутствуют сгенерированные функции" + "отсутствуют сгенерированные функции", ) return dict_func @@ -54,6 +51,16 @@ async def get_client(self): def format_url( self, url_template: str, - path_param: dict[str, int] = None + path_param: dict[str, int] = None, ): return url_template.format(**path_param) + + def filter_query_params(self, **kwargs): + if 'sort' in kwargs or 'sort_field' in kwargs: + sort = kwargs.pop('sort') + sort_field = kwargs['sort_field'] + kwargs[f'sort[{sort_field}]'] = sort + + return { + str(key): value for key, value in kwargs.items() if value is not None + } diff --git a/src/generator2/openapi.yaml b/src/generator2/openapi.yaml index 59df7ac..8dae80f 100644 --- a/src/generator2/openapi.yaml +++ b/src/generator2/openapi.yaml @@ -41,17 +41,20 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type in: query - description: Тип сущности - участник (User) или напоминание (Task). + description: Тип сущности required: true schema: type: string + enum: + - User + - Task responses: '200': description: Успешный запрос @@ -63,30 +66,44 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Поле не может быть пустым value: - detail: BLANK - INCLUSION: - summary: inclusion + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: description: Поле имеет непредусмотренное значение value: - detail: INCLUSION + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /uploads: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -99,50 +116,34 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: '204': - description: Успешный запрос. + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: - employees summary: получение актуального списка всех сотрудников компании description: | - Fetch a paginated list of employees with optional filtering by query. + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/queryParameter' responses: '200': description: Успешный запрос @@ -181,19 +182,32 @@ paths: properties: data: $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /profile/status: get: tags: - status summary: получение информации о своем статусе description: | - Параметры запроса отсутствуют + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. operationId: getStatus responses: '200': @@ -210,14 +224,17 @@ paths: - status summary: новый статус description: | - Создание нового статуса. + Метод для установки себе нового статуса. operationId: putStatus requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/QueryStatus' + type: object + properties: + status: + $ref: '#/components/schemas/Status' responses: '201': description: Объект создан @@ -229,50 +246,71 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Обязательное поле (не может быть пустым) value: - detail: BLANK - TOO_LONG: - summary: too_long + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: description: Слишком длинное значение (пояснения вы получите в поле message) value: - detail: TOO_LONG - INVALID: - summary: invalid + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) value: - detail: INVALID - WRONG_EMOJI: - summary: wrong_emoji + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: description: Emoji статуса не может содержать значения отличные от Emoji символа value: - detail: WRONG_EMOJI + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} delete: tags: - status summary: удаление своего статуса description: | - Параметры запроса отсутствуют + Метод для удаления своего статуса. Параметры запроса отсутствуют. operationId: delStatus responses: '204': - description: Объект успешно удален, тело ответа отсутствует + description: При безошибочном выполнении запроса тело ответа отсутствует content: {} /group_tags/{id}: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -291,62 +329,38 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -359,43 +373,25 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: exclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -404,6 +400,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -411,21 +409,8 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -439,17 +424,30 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} /chats: post: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. При создании беседы или канала вы автоматически становитесь участником. @@ -461,7 +459,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -473,7 +471,7 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: @@ -509,16 +507,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -551,68 +539,18 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - required: false - description: Страница выборки (по умолчанию 1) - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time + - $ref: '#/components/parameters/sortParameter' ############################################### + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/availabilityParameter' + - $ref: '#/components/parameters/last_message_at_afterParameter' + - $ref: '#/components/parameters/last_message_at_beforeParameter' responses: '200': description: Запрос отработал как положено, без ошибок @@ -626,14 +564,14 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -653,16 +591,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -696,7 +624,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -717,8 +645,8 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: @@ -754,34 +682,81 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -800,73 +775,134 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: 'Выход из беседы или канала' - description: |- - Метод для самостоятельного выхода из беседы или канала. - parameters: - - name: id - in: path - required: true - description: 'Уникальный идентификатор беседы или канала.' - schema: - type: integer - responses: - '200': - description: 'Успешно отписан. Тело ответа отсутствует' - '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /messages/{id}/thread: - post: - tags: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: выход из беседы или канала + description: |- + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '200': + description: При безошибочном выполнении запроса тело ответа отсутствуе + '400': + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: - comments - summary: Создание нового треда + summary: создание нового треда description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. operationId: createThread parameters: - name: id @@ -884,37 +920,44 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -944,11 +987,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -973,41 +1011,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - messages @@ -1019,32 +1059,12 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) - schema: - title: per - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - schema: - title: page - type: integer - default: 1 + - $ref: '#/components/parameters/chatParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Successful @@ -1097,41 +1117,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1186,23 +1208,30 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1234,27 +1263,48 @@ paths: items: $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1273,84 +1323,79 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} delete: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1361,124 +1406,65 @@ paths: description: Уникальный идентификатор сообщения. schema: type: integer - - name: code - in: query - required: true - description: Emoji, который нужно удалить. - schema: - type: string + - $ref: '#/components/parameters/reactionParameter' responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path + description: Уникальный идентификатор сообщения required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Список реакций успешно получен. @@ -1491,25 +1477,43 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /tasks: post: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1522,41 +1526,7 @@ paths: type: object properties: task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля + $ref: '#/components/schemas/BaseTask' responses: '201': description: Напоминание успешно создано @@ -1566,70 +1536,196 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки - + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: + parameters: + perParameter50: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + perParameter25: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + pageParameter: + name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + queryParameter: + name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + chatParameter: + name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + sortParameter: + name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + availabilityParameter: + name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + last_message_at_afterParameter: + name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + last_message_at_beforeParameter: + name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + reactionParameter: + name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1656,6 +1752,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1664,6 +1764,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1685,6 +1788,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1694,49 +1802,6 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - FileResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - direct_url: - type: string - DirectResponse: - title: DirectResponse - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1760,45 +1825,74 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. - Status: + BaseResponse: + title: Base Response type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. properties: - emoji: + Content-Disposition: type: string - description: Emoji символ статуса - title: + description: Используемый заголовок + default: attachment + acl: type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object properties: - emoji: + direct_url: type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - QueryCommonMethods: + description: Адрес для загрузки файла + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1812,18 +1906,14 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string + description: тип поля Errors: - title: Errors type: array items: title: Error @@ -1832,18 +1922,23 @@ components: key: title: key type: string + description: Ключ параметра, в котором произошла ошибка value: title: value type: string + description: Значение ключа, которое вызвало ошибку message: title: message type: string + description: Ошибка текстом, который вы можете вывести пользователю code: title: code type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) payload: title: payload type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) Buttons: title: Message Buttons type: array @@ -1870,176 +1965,159 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Base Thread type: object - required: - - entity_id - - content + nullable: true properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id + id: + title: Id type: integer - content: - title: Content - type: string - files: - title: Files - type: array + chat_id: + title: Chat Id + type: integer + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files + type: array + items: + type: object + required: + - key + - name + - file_type + - size + properties: + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + CreateEditFiles: + title: Create&Edit Files + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array items: type: object - required: - - key - - name - - file_type - - size properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' size: title: Size type: integer - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - EditMessages: + description: Размер файла в байтах, отображаемый пользователю + Files: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: array + items: + type: object + properties: + id: + title: Id + type: integer + url: + title: Url + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения - files: - type: object + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object properties: id: title: Id @@ -2047,49 +2125,57 @@ components: chat_id: title: Chat Id type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id + user_id: + title: User Id type: integer + created_at: + title: Created At + type: string + format: date-time + files: + allOf: + - $ref: '#/components/schemas/Files' + title: files + thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + forwarding: + title: Forwarding + type: object nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. Reaction: type: object properties: @@ -2106,81 +2192,8 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2198,6 +2211,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2206,6 +2225,33 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. @@ -2219,6 +2265,97 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + title: Base Custom Properties + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + title: Custom Properties + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: array + items: + type: object + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http diff --git a/src/generator2/pachca.py b/src/generator2/pachca.py deleted file mode 100644 index 00ba0a4..0000000 --- a/src/generator2/pachca.py +++ /dev/null @@ -1,24 +0,0 @@ -import asyncio -from bot import PachcaBot, TOKEN - -if __name__ == '__main__': - - print(id(PachcaBot)) - print(PachcaBot) - pachca = PachcaBot(token=TOKEN) - - print(hasattr(pachca, 'get_common_methods')) - - async def run_pachca(): - print(await pachca.get_employee(id=514505)) - print(await pachca.get_employees()) - print(await pachca.get_tags()) - print(await pachca.get_tags_employees(id=27470)) - #print(await pachca.get_common_methods()) #Возвращает ошибку, нужно прописать обработку если (parameters.query и parameters.required) - - asyncio.run(run_pachca()) - - print(type(pachca)) - print(pachca.__class__) - print(pachca.__class__.__class__) - print(pachca.__class__.__class__.__class__) diff --git a/src/generator2/request_methods.py b/src/generator2/request_methods.py index 3ca45a8..e69de29 100644 --- a/src/generator2/request_methods.py +++ b/src/generator2/request_methods.py @@ -1,250 +0,0 @@ -"""Сгенерированные методы запроса.""" - - - -async def get_common_methods(self, entity_type: str = None): - """Список дополнительных полей - -Метод для получения актуального списка дополнительных полей участников и -напоминаний в вашей компании.""" - client = await self.get_client() - async with client: - url = '/custom_properties' - response = await client.get(url, params={ 'entity_type': entity_type }) - response.raise_for_status() - return response.json() - - -async def get_uploads(self): - """Получение подписи и ключа для загрузки файла - -Возвращает параметры, необходимые для безопасной загрузки файла.""" - client = await self.get_client() - async with client: - url = '/uploads' - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def get_direct_url(self): - """Получение URL для загрузки - -Отправляет запрос для получения URL для безопасной загрузки файла.""" - client = await self.get_client() - async with client: - url = '/direct_url' - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def get_employees(self, per: int = None, page: int = None, query: str = None): - """получение актуального списка всех сотрудников компании - -Fetch a paginated list of employees with optional filtering by query.""" - client = await self.get_client() - async with client: - url = '/users' - response = await client.get(url, params={ 'per': per, 'page': page, 'query': query }) - response.raise_for_status() - return response.json() - - -async def get_employee(self, id: int): - """получение информации о сотруднике - -Метод для получения информации о сотруднике. Для получения сотрудника вам -необходимо знать его id и указать его в URL запроса.""" - client = await self.get_client() - async with client: - url = self.format_url('/users/{id}', {'id': id}) - response = await client.get(url) - response.raise_for_status() - return response.json() - - -async def del_status(self): - """удаление своего статуса - -Параметры запроса отсутствуют""" - client = await self.get_client() - async with client: - url = '/profile/status' - response = await client.delete(url) - response.raise_for_status() - return response.json() - - -async def get_tag(self, id: int): - """Информация о теге - -Параметры запроса отсутствуют""" - client = await self.get_client() - async with client: - url = self.format_url('/group_tags/{id}', {'id': id}) - response = await client.get(url) - response.raise_for_status() - return response.json() - - -async def get_tags(self, per: int = None, page: int = None): - """Список тегов сотрудников - -Метод для получения актуального списка тегов сотрудников.""" - client = await self.get_client() - async with client: - url = '/group_tags' - response = await client.get(url, params={ 'per': per, 'page': page }) - response.raise_for_status() - return response.json() - - -async def get_tags_employees(self, id: int, per: int = None, page: int = None): - """получение актуального списка сотрудников тега - -Метод для получения актуального списка сотрудников тега.""" - client = await self.get_client() - async with client: - url = self.format_url('/group_tags/{id}/users', {'id': id}) - response = await client.get(url, params={ 'per': per, 'page': page }) - response.raise_for_status() - return response.json() - - -async def create_chat(self): - """Новая беседа или канал - -Метод для создания новой беседы или нового канала. При создании беседы или -канала вы автоматически становитесь участником.""" - client = await self.get_client() - async with client: - url = '/chats' - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def get_chat(self, id: int): - """Информация о беседе или канале - -Получения информации о беседе или канале. Для получения беседы или канала вам -необходимо знать её id и указать его в URL запроса.""" - client = await self.get_client() - async with client: - url = self.format_url('/chats/{id}', {'id': id}) - response = await client.get(url) - response.raise_for_status() - return response.json() - - -async def post_members_to_chats(self, id: int): - """добавление пользователей в состав участников - -Метод для добавления пользователей в состав участников беседы или канала.""" - client = await self.get_client() - async with client: - url = self.format_url('/chats/{id}/members', {'id': id}) - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def post_tags_to_chats(self, id: int): - """добавление тегов в состав участников беседы или канала - -Метод для добавления тегов в состав участников беседы или канала.""" - client = await self.get_client() - async with client: - url = self.format_url('/chats/{id}/group_tags', {'id': id}) - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def leave_chat(self, id: int): - """Выход из беседы или канала - -Метод для самостоятельного выхода из беседы или канала.""" - client = await self.get_client() - async with client: - url = self.format_url('/chats/{id}/leave', {'id': id}) - response = await client.delete(url) - response.raise_for_status() - return response.json() - - -async def create_thread(self, id: int): - """Создание нового треда - -Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был -создан тред, то в ответе вернётся информация об уже созданном ранее треде.""" - client = await self.get_client() - async with client: - url = self.format_url('/messages/{id}/thread', {'id': id}) - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def create_message(self): - """создание нового сообщения - -Метод для отправки сообщения в беседу или канал, личного сообщения пользователю -или комментария в тред. При использовании entity_type: "discussion" (или -просто без указания entity_type) допускается отправка любого chat_id в поле -entity_id. То есть, сообщение можно отправить зная только идентификатор чата. -При этом, вы имеете возможность отправить сообщение в тред по его -идентификатору или личное сообщение по идентификатору пользователя. Для -отправки личного сообщения пользователю создавать чат не требуется. Достаточно -указать entity_type: "user" и идентификатор пользователя. Чат будет создан -автоматически, если между вами ещё не было переписки. Между двумя -пользователями может быть только один личный чат.""" - client = await self.get_client() - async with client: - url = '/messages' - response = await client.post(url) - response.raise_for_status() - return response.json() - - -async def edit_message(self, id: int): - """Редактирование сообщения - -Метод для редактирования сообщения или комментария.""" - client = await self.get_client() - async with client: - url = self.format_url('/messages/{id}', {'id': id}) - response = await client.put(url) - response.raise_for_status() - return response.json() - - -async def delete_message_reactions(self, id: int, code: str = None): - """Удаление реакции - -Метод для удаления реакции на сообщение. Удалить можно только те реакции, -которые были поставлены авторизованным пользователем.""" - client = await self.get_client() - async with client: - url = self.format_url('/messages/{id}/reactions', {'id': id}) - response = await client.delete(url, params={ 'code': code }) - response.raise_for_status() - return response.json() - - -async def create_task(self): - """Метод для создания нового напоминания. - -При создании напоминания обязательным условием является указания типа -напоминания: звонок, встреча, простое напоминание, событие или письмо. При -этом не требуется дополнительное описание - вы просто создадите напоминание с -соответствующим текстом. Если вы укажите описание напоминания - то именно оно и -станет текстом напоминания. У напоминания должны быть ответственные, если их не -указывать - ответственным назначаетесь вы.""" - client = await self.get_client() - async with client: - url = '/tasks' - response = await client.post(url) - response.raise_for_status() - return response.json() diff --git a/src/generator2/request_methods_gen.py b/src/generator2/request_methods_gen.py index 59ae3fe..e333ba7 100644 --- a/src/generator2/request_methods_gen.py +++ b/src/generator2/request_methods_gen.py @@ -1,16 +1,19 @@ -import re import os +import re import textwrap +from typing import Union +from httpx import codes from openapi_parser import parse -from openapi_parser.specification import Path, Specification, DataType +from openapi_parser.specification import DataType, Path, Specification def get_obj_openapi_spec( - path_to_file='openapi.yaml' + path_to_file='openapi.yaml', ) -> Specification: """Читает спецификацию openapi из файла openapi.yaml и возвращает - спецификацию в виде объекта Specification библиотеки openapi_parser""" + спецификацию в виде объекта Specification библиотеки openapi_parser + """ base_dir = os.path.dirname(os.path.abspath(__file__)) full_path = os.path.join(base_dir, path_to_file) @@ -21,23 +24,36 @@ def get_obj_openapi_spec( def get_template_methods( - name_func, - url, - method_request, - param_path: dict, - param_query: dict, - docstring + name_func: str, + url: str, + method_request: str, + docstring: str, + param_path: dict[str, Union[str, dict]] = None, + param_query: dict[str, Union[str, dict]] = None, + name_request_schema: str = None, + name_response_schema: str = None, + name_response_error_schema: str = None, ): """Возвращает шаблон генерируемой функции. - Вызывается в функции gen_template""" + Вызывается в функции gen_templates + """ function_params = [] + if param_path: for name, type_param in param_path.items(): function_params.append(f'{name}: {type_param}') if param_query: - for name, type_param in param_query.items(): - function_params.append(f'{name}: {type_param} = None') - function_params = ", ".join(["self"] + function_params) + for name, data_param in param_query.items(): + type_param = data_param['type'] + default_value = data_param['default'] + if name in {'sort', 'sort_field'}: + default_value = f"'{default_value}'" + function_params.append(f'{name}: {type_param} = {default_value}') + + if name_request_schema: + function_params = ", ".join(["self", f"data: {name_request_schema}"] + function_params) + else: + function_params = ", ".join(["self"] + function_params) format_url = ( f"url = self.format_url('{url}', {{" @@ -46,53 +62,66 @@ def get_template_methods( if param_path else f"url = '{url}'" ) - get_response = ( - f"response = await client.{method_request}(url" - + (f", params={param_query}" if param_query else "") - + ")" - ) - + filter_params = "" if param_query: - query_params = ", ".join([ - f"'{name}': {name}" for name in param_query.keys() + query_params_for_filter = ", ".join([ + f"{name}={name}" for name in param_query.keys() ]) - get_response = f"response = await client.{method_request}(url, params={{ {query_params} }})" + filter_params = f'query_params=self.filter_query_params({query_params_for_filter})' + + if name_request_schema: + get_response = f'response = await client.{method_request}(url, json=data.model_dump())' + elif param_query: + get_response = f'response = await client.{method_request}(url, params=query_params)' else: get_response = f"response = await client.{method_request}(url)" + response_handling = "" + if name_response_schema: + response_handling += f""" + if response.is_success: + return {name_response_schema}.model_validate_json(response.text)""" + if name_response_error_schema: + response_handling += f""" + if response.is_client_error: + return {name_response_error_schema}.model_validate_json(response.text)""" + + response_annotation = f" -> {name_response_schema}" if name_response_schema else "" + filter_params_code = f"\n {filter_params}" if filter_params else "" + return f""" -async def {name_func}({function_params}): +async def {name_func}({function_params}){response_annotation}: {docstring} client = await self.get_client() async with client: - {format_url} - {get_response} - response.raise_for_status() - return response.json() + {format_url}{filter_params_code} + {get_response}{response_handling} """ def format_docstring(summary: str, description: str, max_width: int = 79): """Редактирует длины строк докстринг - генерируемых функций в соответствиие с PEP8""" + генерируемых функций в соответствиие с PEP8 + """ formatted_summary = "\n".join(textwrap.wrap(summary, width=max_width)) formatted_description = "\n".join( - textwrap.wrap(description, width=max_width) + textwrap.wrap(description, width=max_width), ) return f'"""{formatted_summary}\n\n{formatted_description}"""' def format_name_func(operation_id: str): - "Возвращает название генерируемой функции запроса в требуемом формате" + """Возвращает название генерируемой функции запроса в требуемом формате""" return '_'.join( - re.findall(r'[a-z]+|[A-Z][^A-Z]*', operation_id) + re.findall(r'[a-z]+|[A-Z][^A-Z]*', operation_id), ).lower() def get_python_type(schema_type: DataType): """Сопоставляет текущий тип данных параметра с типом данных Python - и возвращает его""" + и возвращает его + """ type_mapping = { DataType.STRING: "str", DataType.INTEGER: "int", @@ -105,44 +134,77 @@ def get_python_type(schema_type: DataType): return type_mapping.get(schema_type, None) -def gen_template(paths: Path) -> list[str]: +def gen_templates(paths: Path) -> list[str]: """Собирает параметры запроса всех paths спецификации - Возвращает список шаблонов функций""" + передает их в функицю get_template_methods + Возвращает список шаблонов функций + """ functions = [] for path in paths: url = path.url for operation in path.operations: + name_request_body_schema = None + response_name_schema = None + response_error_name_schema = None method_request = operation.method.value.lower() function_name = format_name_func(operation.operation_id) docstring = format_docstring( - operation.summary, operation.description + operation.summary, operation.description, ) + if operation.request_body: + name_request_body_schema = operation.operation_id.capitalize() + for response in operation.responses: + if codes.is_success(response.code) and response.content: + response_name_schema = ( + f'Response{operation.operation_id.capitalize()}' + f'{operation.method.value.capitalize()}' + f'{str(response.code).capitalize()}' + ) + if codes.is_client_error(response.code): + response_error_name_schema = ( + f'Response{operation.operation_id.capitalize()}' + f'{operation.method.value.capitalize()}' + f'{str(response.code).capitalize()}' + ) param_path = {} param_query = {} - #for obj in operation.request_body.content: - # print(obj.schema.title) - #print(operation.request_body.content) for param in operation.parameters: if param.location.value == 'path': schema_type = get_python_type(param.schema.type) - print(schema_type) param_path[param.name] = schema_type if param.location.value == 'query': schema_type = get_python_type(param.schema.type) - param_query[param.name] = schema_type - - # print(url) - functions.append( - get_template_methods( - function_name, - url, - method_request, - param_path, - param_query, - docstring + if param.name == 'sort[id]': + default_value_sort = param.schema.default + param.name = 'sort' + param_query['sort_field'] = { + 'type': 'str', + 'default': 'id' + } + param_query[param.name] = { + 'type': schema_type, + 'default': default_value_sort + } + continue + param_query[param.name] = { + 'type': schema_type, + 'default': None, + } + + functions.append( + get_template_methods( + function_name, + url, + method_request, + docstring, + param_path, + param_query, + name_request_body_schema, + response_name_schema, + response_error_name_schema + ), ) - ) return functions @@ -151,11 +213,10 @@ def gen_template(paths: Path) -> list[str]: spec: Specification = get_obj_openapi_spec() paths: list[Path] = spec.paths - - templates = gen_template(paths) + templates = gen_templates(paths) with open( - 'src/generator2/request_methods.py', 'w', encoding='utf-8' + 'src/generator2/request_methods.py', 'w', encoding='utf-8', ) as file: file.write('"""Сгенерированные методы запроса."""\n\n') for template in templates: From 27ffd7bfe6116baa5d6023b303bff083c769a44a Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Mon, 6 Jan 2025 01:49:54 +0500 Subject: [PATCH 149/296] library_sanym_ver1 --- src/builder/Makefile | 21 + src/builder/Pipfile | 41 + src/builder/Pipfile.lock | 471 ++++ src/builder/README.md | 8 +- src/builder/requirements.txt | 30 + src/builder/requirements_all.txt | 35 + src/builder/setup.py | 34 + src/generator1/openapi.yaml | 2207 ++++++++++-------- src/generator1/pachca.py | 4 +- src/openapi.yaml | 131 +- src/repository/pachca-1.1.0-py3-none-any.whl | Bin 0 -> 142710 bytes src/repository/pachca-1.1.1-py3-none-any.whl | Bin 0 -> 142709 bytes 12 files changed, 1874 insertions(+), 1108 deletions(-) create mode 100644 src/builder/Makefile create mode 100644 src/builder/Pipfile create mode 100644 src/builder/Pipfile.lock create mode 100644 src/builder/requirements.txt create mode 100644 src/builder/requirements_all.txt create mode 100644 src/builder/setup.py create mode 100644 src/repository/pachca-1.1.0-py3-none-any.whl create mode 100644 src/repository/pachca-1.1.1-py3-none-any.whl diff --git a/src/builder/Makefile b/src/builder/Makefile new file mode 100644 index 0000000..dcc53b4 --- /dev/null +++ b/src/builder/Makefile @@ -0,0 +1,21 @@ +help: + @echo "Tasks in \033[1;32mdemo\033[0m:" + @cat Makefile + +lint: + mypy src --ignore-missing-imports + flake8 src --ignore=$(shell cat .flakeignore) + +dev: + pip install -e . + +test: dev + + +build: clean + + pip install wheel + python setup.py bdist_wheel --dist-dir=../repository/ + +clean: + @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ diff --git a/src/builder/Pipfile b/src/builder/Pipfile new file mode 100644 index 0000000..cb2d816 --- /dev/null +++ b/src/builder/Pipfile @@ -0,0 +1,41 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +annotated-types = "==0.7.0" +anyio = "==4.8.0" +attrs = "==24.3.0" +certifi = "==2024.12.14" +click = "==8.1.8" +colorama = "==0.4.6" +distlib = "==0.3.9" +h11 = "==0.14.0" +httpcore = "==1.0.7" +httpx = "==0.28.1" +idna = "==3.10" +jinja2 = "==3.1.5" +markdown-it-py = "==3.0.0" +markupsafe = "==3.0.2" +mdurl = "==0.1.2" +packaging = "==24.2" +platformdirs = "==4.3.6" +pydantic = "==2.10.4" +pydantic-core = "==2.27.2" +pygments = "==2.19.0" +python-dateutil = "==2.9.0.post0" +python-dotenv = "==1.0.1" +rich = "==13.9.4" +ruff = "==0.8.6" +shellingham = "==1.5.4" +six = "==1.17.0" +sniffio = "==1.3.1" +typer = "==0.15.1" +typing-extensions = "==4.12.2" +virtualenv = "==20.28.1" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/src/builder/Pipfile.lock b/src/builder/Pipfile.lock new file mode 100644 index 0000000..2763ec2 --- /dev/null +++ b/src/builder/Pipfile.lock @@ -0,0 +1,471 @@ +{ + "_meta": { + "hash": { + "sha256": "e0c39def9c9289d0f87a4fcd85226e903d2df379e5e2a32568808f15f3e5e262" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, + "anyio": { + "hashes": [ + "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", + "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==4.8.0" + }, + "attrs": { + "hashes": [ + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.3.0" + }, + "certifi": { + "hashes": [ + "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", + "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==2024.12.14" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==0.4.6" + }, + "distlib": { + "hashes": [ + "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", + "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403" + ], + "index": "pypi", + "version": "==0.3.9" + }, + "filelock": { + "hashes": [ + "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", + "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435" + ], + "markers": "python_version >= '3.8'", + "version": "==3.16.1" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "httpcore": { + "hashes": [ + "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", + "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.0.7" + }, + "httpx": { + "hashes": [ + "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", + "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.28.1" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "jinja2": { + "hashes": [ + "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", + "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==3.1.5" + }, + "markdown-it-py": { + "hashes": [ + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==3.0.0" + }, + "markupsafe": { + "hashes": [ + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.0.2" + }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.1.2" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "platformdirs": { + "hashes": [ + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.3.6" + }, + "pydantic": { + "hashes": [ + "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", + "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.10.4" + }, + "pydantic-core": { + "hashes": [ + "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", + "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", + "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", + "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", + "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", + "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", + "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", + "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", + "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", + "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", + "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", + "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", + "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", + "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", + "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", + "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", + "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", + "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", + "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", + "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", + "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", + "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", + "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", + "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", + "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", + "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", + "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", + "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", + "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", + "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", + "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", + "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", + "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", + "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", + "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", + "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", + "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", + "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", + "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", + "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", + "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", + "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", + "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", + "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", + "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", + "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", + "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", + "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", + "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", + "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", + "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", + "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", + "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", + "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", + "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", + "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", + "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", + "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", + "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", + "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", + "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", + "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", + "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", + "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", + "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", + "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", + "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", + "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", + "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", + "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", + "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", + "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", + "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", + "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", + "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", + "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", + "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", + "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", + "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", + "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", + "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", + "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", + "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", + "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", + "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", + "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", + "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", + "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", + "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", + "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", + "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", + "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", + "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", + "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", + "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", + "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", + "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", + "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", + "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", + "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.27.2" + }, + "pygments": { + "hashes": [ + "sha256:4755e6e64d22161d5b61432c0600c923c5927214e7c956e31c23923c89251a9b", + "sha256:afc4146269910d4bdfabcd27c24923137a74d562a23a320a41a55ad303e19783" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.19.0" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.9.0.post0" + }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.0.1" + }, + "rich": { + "hashes": [ + "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", + "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.0'", + "version": "==13.9.4" + }, + "ruff": { + "hashes": [ + "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", + "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", + "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", + "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", + "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", + "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", + "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1", + "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", + "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", + "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162", + "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", + "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", + "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", + "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", + "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", + "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764", + "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807", + "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.8.6" + }, + "shellingham": { + "hashes": [ + "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", + "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.5.4" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, + "sniffio": { + "hashes": [ + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.3.1" + }, + "typer": { + "hashes": [ + "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", + "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.15.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, + "virtualenv": { + "hashes": [ + "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb", + "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==20.28.1" + } + }, + "develop": {} +} diff --git a/src/builder/README.md b/src/builder/README.md index a0a9484..8e4a48e 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -1 +1,7 @@ -Инструменты для генерации библиотеки \ No newline at end of file +# Инструменты для генерации библиотеки + +## Создать версию библиотеки при помощи команды (пример): +- export PACKAGE_VERSION='1.1.0' + +## Запуск создания библиотеки при помощи команды: +- make build \ No newline at end of file diff --git a/src/builder/requirements.txt b/src/builder/requirements.txt new file mode 100644 index 0000000..5f6123f --- /dev/null +++ b/src/builder/requirements.txt @@ -0,0 +1,30 @@ +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +click==8.1.8 +colorama==0.4.6 +distlib==0.3.9 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +idna==3.10 +Jinja2==3.1.5 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdurl==0.1.2 +packaging==24.2 +platformdirs==4.3.6 +pydantic==2.10.4 +pydantic_core==2.27.2 +Pygments==2.19.0 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +rich==13.9.4 +ruff==0.8.6 +shellingham==1.5.4 +six==1.17.0 +sniffio==1.3.1 +typer==0.15.1 +typing_extensions==4.12.2 +virtualenv==20.28.1 diff --git a/src/builder/requirements_all.txt b/src/builder/requirements_all.txt new file mode 100644 index 0000000..72ef60d --- /dev/null +++ b/src/builder/requirements_all.txt @@ -0,0 +1,35 @@ +annotated-types==0.7.0 +anyio==4.8.0 +attrs==24.3.0 +certifi==2024.12.14 +click==8.1.8 +colorama==0.4.6 +distlib==0.3.9 +filelock==3.16.1 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +idna==3.10 +Jinja2==3.1.5 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdurl==0.1.2 +openapi-python-client==0.23.0 +packaging==24.2 +pipenv==2024.4.0 +platformdirs==4.3.6 +pydantic==2.10.4 +pydantic_core==2.27.2 +Pygments==2.19.0 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +rich==13.9.4 +ruamel.yaml==0.18.9 +ruamel.yaml.clib==0.2.12 +ruff==0.8.6 +shellingham==1.5.4 +six==1.17.0 +sniffio==1.3.1 +typer==0.15.1 +typing_extensions==4.12.2 +virtualenv==20.28.1 diff --git a/src/builder/setup.py b/src/builder/setup.py new file mode 100644 index 0000000..6cb24f4 --- /dev/null +++ b/src/builder/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup, find_packages + +import json +import os +from pathlib import Path + +this_directory = Path(__file__).parent +long_description = (this_directory / "../../README.md").read_text() + + +def read_pipenv_dependencies(fname): + """Получаем из Pipfile.lock зависимости по умолчанию.""" + filepath = os.path.join(os.path.dirname(__file__), fname) + with open(filepath) as lockfile: + lockjson = json.load(lockfile) + return [dependency for dependency in lockjson.get('default')] + + +if __name__ == '__main__': + setup( + name='pachca', + long_description=long_description, + long_description_content_type='text/markdown', + version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), + package_dir={'': '../generator1/pachca-api-open-api-3-0-client'}, + packages=find_packages( + '../generator1/pachca-api-open-api-3-0-client', include=[ + 'pachca_api_open_api_3_0_client*'] + ), + description='A pachca_api package.', + install_requires=[ + *read_pipenv_dependencies('Pipfile.lock'), + ] + ) diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml index dec1f58..4527bb9 100644 --- a/src/generator1/openapi.yaml +++ b/src/generator1/openapi.yaml @@ -41,17 +41,20 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type in: query - description: Тип сущности - участник (User) или напоминание (Task). + description: Тип сущности required: true schema: type: string + enum: + - User + - Task responses: '200': description: Успешный запрос @@ -63,30 +66,44 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Поле не может быть пустым value: - detail: BLANK - INCLUSION: - summary: inclusion + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: description: Поле имеет непредусмотренное значение value: - detail: INCLUSION + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /uploads: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -99,50 +116,34 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: '204': - description: Успешный запрос. + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: - employees summary: получение актуального списка всех сотрудников компании description: | - Fetch a paginated list of employees with optional filtering by query. + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/queryParameter' responses: '200': description: Успешный запрос @@ -181,19 +182,32 @@ paths: properties: data: $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /profile/status: get: tags: - status summary: получение информации о своем статусе description: | - Параметры запроса отсутствуют + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. operationId: getStatus responses: '200': @@ -210,14 +224,17 @@ paths: - status summary: новый статус description: | - Создание нового статуса. + Метод для установки себе нового статуса. operationId: putStatus requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/QueryStatus' + type: object + properties: + status: + $ref: '#/components/schemas/Status' responses: '201': description: Объект создан @@ -229,50 +246,71 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Обязательное поле (не может быть пустым) value: - detail: BLANK - TOO_LONG: - summary: too_long + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: description: Слишком длинное значение (пояснения вы получите в поле message) value: - detail: TOO_LONG - INVALID: - summary: invalid + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) value: - detail: INVALID - WRONG_EMOJI: - summary: wrong_emoji + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: description: Emoji статуса не может содержать значения отличные от Emoji символа value: - detail: WRONG_EMOJI + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} delete: tags: - status summary: удаление своего статуса description: | - Параметры запроса отсутствуют + Метод для удаления своего статуса. Параметры запроса отсутствуют. operationId: delStatus responses: '204': - description: Объект успешно удален, тело ответа отсутствует + description: При безошибочном выполнении запроса тело ответа отсутствует content: {} /group_tags/{id}: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -291,62 +329,38 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -359,43 +373,25 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: exclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -404,6 +400,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -411,21 +409,8 @@ paths: required: true schema: type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Успешный запрос @@ -439,20 +424,33 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} /chats: post: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -461,7 +459,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -473,7 +471,7 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: @@ -509,16 +507,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -551,68 +539,18 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - required: false - description: Страница выборки (по умолчанию 1) - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time + - $ref: '#/components/parameters/sortParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' + - $ref: '#/components/parameters/availabilityParameter' + - $ref: '#/components/parameters/last_message_at_afterParameter' + - $ref: '#/components/parameters/last_message_at_beforeParameter' responses: '200': description: Запрос отработал как положено, без ошибок @@ -626,14 +564,14 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -653,16 +591,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -696,7 +624,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -717,8 +645,8 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: @@ -754,34 +682,81 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -800,73 +775,134 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: 'Выход из беседы или канала' - description: |- - Метод для самостоятельного выхода из беседы или канала. - parameters: - - name: id - in: path - required: true - description: 'Уникальный идентификатор беседы или канала.' - schema: - type: integer - responses: - '200': - description: 'Успешно отписан. Тело ответа отсутствует' - '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /messages/{id}/thread: - post: - tags: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: выход из беседы или канала + description: |- + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '200': + description: При безошибочном выполнении запроса тело ответа отсутствуе + '400': + description: Пояснения ошибки + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: - comments - summary: Создание нового треда + summary: создание нового треда description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. operationId: createThread parameters: - name: id @@ -884,37 +920,44 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -944,11 +987,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -973,41 +1011,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - messages @@ -1019,32 +1059,12 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) - schema: - title: per - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - schema: - title: page - type: integer - default: 1 + - $ref: '#/components/parameters/chatParameter' + - $ref: '#/components/parameters/perParameter25' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Successful @@ -1097,41 +1117,43 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1186,23 +1208,30 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1234,27 +1263,48 @@ paths: items: $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1273,84 +1323,79 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: "204": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки. + errors: + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} delete: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1361,124 +1406,65 @@ paths: description: Уникальный идентификатор сообщения. schema: type: integer - - name: code - in: query - required: true - description: Emoji, который нужно удалить. - schema: - type: string + - $ref: '#/components/parameters/reactionParameter' responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: type: object properties: errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path + description: Уникальный идентификатор сообщения required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 + - $ref: '#/components/parameters/perParameter50' + - $ref: '#/components/parameters/pageParameter' responses: '200': description: Список реакций успешно получен. @@ -1491,25 +1477,43 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + type: object + properties: + errors: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /tasks: post: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1522,41 +1526,7 @@ paths: type: object properties: task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля + $ref: '#/components/schemas/BaseTask' responses: '201': description: Напоминание успешно создано @@ -1566,70 +1536,196 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: type: object properties: - error: - type: string - description: Описание ошибки - + errors: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: + parameters: + perParameter50: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + perParameter25: + name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + pageParameter: + name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + queryParameter: + name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + chatParameter: + name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + sortParameter: + name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + availabilityParameter: + name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + last_message_at_afterParameter: + name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + last_message_at_beforeParameter: + name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + reactionParameter: + name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1656,6 +1752,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1664,6 +1764,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1685,6 +1788,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1694,48 +1802,6 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - FileResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - direct_url: - type: string - DirectResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1759,45 +1825,74 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. - Status: + BaseResponse: + title: Base Response type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. properties: - emoji: + Content-Disposition: type: string - description: Emoji символ статуса - title: + description: Используемый заголовок + default: attachment + acl: type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object properties: - emoji: + direct_url: type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - QueryCommonMethods: + description: Адрес для загрузки файла + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1811,18 +1906,14 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string + description: тип поля Errors: - title: Errors type: array items: title: Error @@ -1831,18 +1922,23 @@ components: key: title: key type: string + description: Ключ параметра, в котором произошла ошибка value: title: value type: string + description: Значение ключа, которое вызвало ошибку message: title: message type: string + description: Ошибка текстом, который вы можете вывести пользователю code: title: code type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) payload: title: payload type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) Buttons: title: Message Buttons type: array @@ -1869,176 +1965,153 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Base Thread + type: object + properties: + id: + type: integer + description: Идентификатор поля + chat_id: + type: integer + description: Идентификатор поля чата + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files type: object required: - - entity_id - - content + - key + - name + - file_type properties: - entity_type: - title: Entity Type + key: type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: type: string - files: + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + Files: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object title: Files - type: array - items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - size: - title: Size - type: integer - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - EditMessages: + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения - files: - type: object + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - discussion + - user + - thread + default: discussion + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object properties: id: title: Id @@ -2046,49 +2119,57 @@ components: chat_id: title: Chat Id type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id + user_id: + title: User Id type: integer + created_at: + title: Created At + type: string + format: date-time + files: + allOf: + - $ref: '#/components/schemas/Files' + title: files + thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + forwarding: + title: Forwarding + type: object nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + default: null + properties: + original_message_id: + title: Origin Message Id + type: integer + description: Идентификатор оригинального сообщения + original_chat_id: + title: Original Chat Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + author_id: + title: Author Id + type: integer + description: Идентификатор чата, в котором находится оригинальное сообщение + original_created_at: + title: Original Created At + type: integer + description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + original_thread_id: + title: Original Thread Id + type: integer + nullable: true + description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_message_id: + title: Original Thread Message Id + type: integer + nullable: true + description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. + original_thread_parent_chat_id: + title: Original Thread Parent Chat Id + type: integer + nullable: true + description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. Reaction: type: object properties: @@ -2105,81 +2186,8 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2197,6 +2205,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2205,6 +2219,33 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. @@ -2218,6 +2259,98 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index bf5bef7..5cddfd3 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -4,9 +4,9 @@ from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, ) -from pachca_api_open_api_3_0_client.models.query_chat import QueryChat +from pachca_api_open_api_3_0_client.models.chat import Chat -query_chat = QueryChat(name='test') +query_chat = Chat(name='test') chat_body = CreateChatBody(chat=query_chat) diff --git a/src/openapi.yaml b/src/openapi.yaml index a2bf3a7..4527bb9 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -1968,14 +1968,13 @@ components: BaseThread: title: Base Thread type: object - nullable: true properties: id: - title: Id type: integer + description: Идентификатор поля chat_id: - title: Chat Id type: integer + description: Идентификатор поля чата Thread: allOf: - $ref: '#/components/schemas/BaseThread' @@ -1994,55 +1993,50 @@ components: Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. BaseFiles: title: Base Files + type: object + required: + - key + - name + - file_type + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: type: array items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - CreateEditFiles: - title: Create&Edit Files - allOf: + allOf: - $ref: '#/components/schemas/BaseFiles' - - type: array - items: - type: object - properties: - size: - title: Size - type: integer - description: Размер файла в байтах, отображаемый пользователю + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю Files: - allOf: + type: array + items: + allOf: - $ref: '#/components/schemas/BaseFiles' - - type: array - items: - type: object - properties: - id: - title: Id - type: integer - url: - title: Url - type: string - description: Прямая временная ссылка на скачивание файла + - type: object + title: Files + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла BeforeBaseMessages: title: Before Base Messages type: object @@ -2083,10 +2077,10 @@ components: title: Entity Type type: string enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' + - discussion + - user + - thread + default: discussion entity_id: title: Entity Id type: integer @@ -2267,23 +2261,22 @@ components: type: integer BaseCustomProperties: title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: type: array items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - title: Custom Properties - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: array - items: - type: object + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties properties: name: type: string @@ -2333,8 +2326,10 @@ components: type: integer description: Массив идентификаторов пользователей custom_properties: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' Task: allOf: - $ref: '#/components/schemas/BaseTask' diff --git a/src/repository/pachca-1.1.0-py3-none-any.whl b/src/repository/pachca-1.1.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..e977da2d8bcad5c5d54972cbd5f3cc2edae5feab GIT binary patch literal 142710 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%0DL$%|rbe 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 + query_chat = BaseChat(name='test500_2') + chat_body = CreateChatBody(chat=query_chat) + # <-- + # запрос на создание беседы + chat_create = asyncio.create_task( + pachca.createChat(body=chat_body)) + chat_response = await chat_create + print(chat_response) + print('*' * 60) + + # запрос на получение списка бесед и каналов + print(await asyncio.create_task(pachca.getChats())) + print('*' * 60) + + # запрос на получение информации о беседе + print(await asyncio.create_task( + pachca.getChat(id=chat_response.data.id)) + ) + print('*' * 60) + + # подготовка запроса на создание сообщения в созданную беседу --> + create_message = CreateMessages( + entity_id=chat_response.data.id, content='Super puper') + message_body = CreateMessageBody(message=create_message) + # <-- + # запрос на создание сообщения в созданную беседу + message_create = asyncio.create_task( pachca.createMessage(body=message_body)) - task4 = asyncio.create_task(pachca.leaveChat(id=111)) - task5 = asyncio.create_task(pachca.deleteMessageReactions( - id=123, code='😭')) - - - print(await task1) - print('*' * 30) - print(await task2) - print('*' * 30) - print(await task3) - print('*' * 30) - print(await task4) - print('*' * 30) - print(await task5) - -id=17945380 + message_response = await message_create + print(message_response) + print('*' * 60) + + # создание треда к созданному сообщению + thread_create = asyncio.create_task( + pachca.createThread(id=message_response.data.id) + ) + print(await thread_create) + print('*' * 60) + + # запрос на получение списка сообщений + print(await asyncio.create_task( + pachca.getListMessage(chat_id=chat_response.data.id)) + ) + print('*' * 60) + + # запрос на получение сообщения + print(await asyncio.create_task( + pachca.getMessage(id=message_response.data.id)) + ) + print('*' * 60) + ''' + Запрос проходит успешно, но в yaml схема ответа прописана не корректно. + Поэтому успешный ответ приводит AttributeError. + # подготовка запроса на редактирование сообщения --> + edit_meassage = EditMessages(content='NOT SUPER PUPER') + edit_message_body = EditMessageBody(message=edit_meassage) + # <-- + # запрос на редактирование сообщения + print(await asyncio.create_task( + pachca.editMessage( + id=message_response.data.id, body=edit_message_body) + ) + ) + print('*' * 60) + ''' + + # подготовка запроса на добавление реакции к сообщению --> + post_reactions = CodeReaction(code='😭') + # <-- + # запрос на добавление реакции к сообщению + print(await asyncio.create_task( + pachca.postMessageReactions( + id=message_response.data.id, body=post_reactions) + ) + ) + print('*' * 60) + + # подготовка запроса на получение списка реакций к сообщению --> + # <-- + # запрос на получение списка реакций + print(await asyncio.create_task( + pachca.getMessageReactions(id=message_response.data.id)) + ) + print('*' * 60) + + # запрос на удаление реакции + print(await asyncio.create_task( + pachca.deleteMessageReactions(id=message_response.data.id, code='😭') + ) + ) + print('*' * 60) + + # подготовка запроса на создание напоминания --> + create_body_task = CreateTaskBody( + kind='call', + content='Звонок другу', + due_at=datetime.datetime.now(), + ) + body_task = CreateTaskBody(task=create_body_task) + # <-- + # запрос на создание напоминания + print(await asyncio.create_task(pachca.createTask(body=body_task))) + print('*' * 60) + + # запрос на получения списка пользователей + users_response = await asyncio.create_task(pachca.getEmployees()) + print(users_response) + print('*' * 60) + + # запрос на получение информации о пользователе + print(await asyncio.create_task( + pachca.getEmployee(id=users_response.data[0].id)) + ) + print('*' * 60) + + # подготовка запроса на добавление статуса --> + query_status = PutStatusBody( + emoji='😭', + title='Я не плачу это просто слезы', + expires_at=None + ) + # <-- + # запрос на добавление статуса + print(await asyncio.create_task(pachca.putStatus(body=query_status))) + print('*' * 60) + + # запрос на получение информации о своем статусе + print(await asyncio.create_task(pachca.getStatus())) + print('*' * 60) + + ''' + В client.py отсутствует метод delStatus + # запрос на удаление статуса + print(await asyncio.create_task(pachca.delStatus())) + print('*' * 60) + ''' + + # запрос на получение тегов сотрудников + print(await asyncio.create_task(pachca.getTags())) + print('*' * 60) + + # запрос на получение списка актуальных полей сущности + print(await asyncio.create_task( + pachca.getCommonMethods(entity_type='User')) + ) + print('*' * 60) + + # запрос получения подписи и ключа для загрузки файла + print(await asyncio.create_task(pachca.getUploads())) + print('*' * 60) + if __name__ == '__main__': asyncio.run(main()) From 45118e0bbfe07a083e71462f2d9bbefabed410ff Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sat, 11 Jan 2025 15:52:29 +0300 Subject: [PATCH 206/296] Update README.md --- README.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 127 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 18161a5..87495c6 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,135 @@ -# Шаблон для проектов со стилизатором Ruff +# Парсер OpenAPI для мессенджера "Пачка" -## Основное +Библиотека для работы с API мессенджера "Пачка", написанная на Python. -1. Базовая версия Python - 3.11. -2. В файле `requirements_style.txt` находятся зависимости для стилистики. -3. В каталоге `src` находится базовая структура проекта -4. В файле `srd/requirements.txt` прописываются базовые зависимости. +## 🔖 Цели и задачи проекта -## Стилистика +Основная цель проекта — создание инструмента для преобразования спецификации OpenAPI в Python-пакет. Этот пакет предоставляет структурированный и удобный интерфейс для взаимодействия с открытым API мессенджера "Пачка". Проект включает: -Для стилизации кода используется пакеты `Ruff` и `Pre-commit` +- **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. +- **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. -Проверка стилистики кода осуществляется командой -```shell -ruff check -``` +### Основные функции: +- **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. +- **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. +- **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. +- **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. -Если одновременно надо пофиксить то, что можно поиксить автоматически, то добавляем параметр `--fix` -```shell -ruff check --fix -``` +## 📚 Используемый стек и технологии -Что бы стилистика автоматически проверялась и поправлялась при комитах надо добавить hook pre-commit к git +### Языки и фреймворки: +- **Python 3.12+**: Основной язык для сгенерированного кода. +- **Asyncio**: Обеспечивает асинхронный режим работы кода. -```shell -pre-commit install -``` +### Библиотеки: +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **pydantic**: Для определения моделей данных ввода и вывода. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. + +## 📜 Детали реализации + +### Подготовка OpenAPI-файла: +- Формат: JSON или YAML. +- Версия OpenAPI: 3.0. + +Обязательные секции: +- `openapi`: Версия файла OpenAPI. +- `info`: Общая информация об API. +- `servers`: Данные о серверах для выполнения запросов. +- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. +- `components`: Схемы данных для структур входных и выходных параметров. + +### Генерация кода: +- **Основной объект**: Центральный класс (например, `Pachka`), инициализируемый токеном авторизации. +- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. +- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. +- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. + +### Распространение пакета: +- Сгенерированный код упаковывается для установки через pip или poetry. +- Пакет включает: + - Генератор API-клиента. + - Полную документацию. + - Необходимые метаданные для менеджеров пакетов. + +## Структура проекта + +### Основные компоненты +- **src/generator2/**: + - `bot.py`: Основной класс для работы с API, Метакласс `RequestMethodsCollector` для сбора методов. + - `constants.py`: Константы проекта, Маппинги типов данных, Пути к файлам, HTTP методы. + - `file_writer.py`: Обеспечивает безопасную запись файлов, Создает необходимые директории, Управляет генерацией выходных файлов. + - `yaml_processor.py`: Обрабатывает YAML спецификацию, Генерирует модели запросов и ответов. + - `schema_link_processor.py`: Обрабатывает ссылки на схемы в YAML спецификации. + - `yaml_loader.py`: Загрузка YAML файла спецификации OpenAPI. + +- **requirements.txt**: Список зависимостей генератора с версиями. +- **request_methods_generator.py**: Генерация методов для работы с API на основе OpenAPI спецификации. +- **pachca.py**: Пример использования сгенерированного API клиента. +- **openapi_test.yaml** и **openapi.yaml**: OpenAPI спецификации API, описание эндпоинтов, схем, параметров. +- **src/generator2/models/**: + - `models_response_`: Модели ответов API. + - `models_reqBod_`: Модели запросов API. + +## Установка и использование + +### Инструкция (работать в папке `generator2` при активированном `venv`): +1. Создать файл `.env` в директории `generator2`, с токеном для работы с API пачки. Пример файла: + ``` + TOKEN=ваштокен + ``` +2. Создать и активировать виртуальное окружение, установить зависимости: + - Для Linux/gitBash: + ```bash + python3 -m venv venv + source venv/scripts/activate + pip install -r requirements.txt + ``` + - Для Windows cmd: + ```bash + python -m venv venv + .\venv\scripts\activate + pip install -r requirements.txt + ``` +3. Запустить генерацию клиента: + ```bash + python -m generator2.generator_starter + ``` +4. Запустить пример запроса: + ```bash + python -m generator2.generator2_full.pachca + ``` + Или перейти в `generator2` и запустить модуль: + ```bash + cd generator2 + python -m generator2_full.pachca + ``` + +## Особенности реализации +- Автоматическое определение типов данных. +- Поддержка вложенных моделей. +- Генерация документации на основе описаний из YAML. +- Обработка опциональных полей. +- Поддержка перечислений (Enum). +- Поддержка основных типов HTTP методов (GET, POST, PUT, PATCH, DELETE). +- Автоматическая обработка параметров запроса. + +### Результат генерации +- Типизированные Pydantic модели для запросов и ответов. +- Валидация данных на уровне моделей. +- Поддержка IDE (автодополнение и подсказки типов). + +## Команда проекта + +**Студенты Яндекс Практикума, Team 2**: + +- Алексей Малков +- Дмитрий Костин +- Александр Малыгин +- Дмитрий Бурмистров + +## Дополнительная информация + +- **Исходный код**: [GitHub Repository](#) +- **Документация API**: [Pachca API Documentation](#) From 68f4411e2851e2f5d67427e1d6feadf8382402f9 Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:30:00 +0300 Subject: [PATCH 207/296] Update README.md --- README.md | 182 +++++++++++++++++++++++------------------------------- 1 file changed, 76 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 87495c6..d3c4c90 100644 --- a/README.md +++ b/README.md @@ -1,135 +1,105 @@ # Парсер OpenAPI для мессенджера "Пачка" -Библиотека для работы с API мессенджера "Пачка", написанная на Python. +Библиотека для работы с API мессенджера "Пачка", написанная на Python. 🐍 ## 🔖 Цели и задачи проекта -Основная цель проекта — создание инструмента для преобразования спецификации OpenAPI в Python-пакет. Этот пакет предоставляет структурированный и удобный интерфейс для взаимодействия с открытым API мессенджера "Пачка". Проект включает: +Основная цель проекта — создание инструмента для преобразования спецификации OpenAPI в Python-пакет. 📋 +Этот пакет предоставляет структурированный и удобный интерфейс для взаимодействия с открытым API мессенджера "Пачка". 🌐 -- **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. -- **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. +Проект включает: +- 🚀 **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. +- 📦 **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. -### Основные функции: -- **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. -- **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. -- **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. -- **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. +### 🔧 Основные функции: +- 🌐 **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. +- 📂 **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. +- 🧩 **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. +- 📖 **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. + +--- ## 📚 Используемый стек и технологии -### Языки и фреймворки: -- **Python 3.12+**: Основной язык для сгенерированного кода. -- **Asyncio**: Обеспечивает асинхронный режим работы кода. +### 🛠️ Языки и фреймворки: +- 🐍 **Python 3.12+**: Основной язык для сгенерированного кода. +- ⚡ **asyncio**: Обеспечивает асинхронный режим работы кода. + +### 📦 Библиотеки: +- 🌐 **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- 🧑‍💻 **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. +- 🗂️ **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- 📄 **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. -### Библиотеки: -- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **pydantic**: Для определения моделей данных ввода и вывода. -- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +--- ## 📜 Детали реализации -### Подготовка OpenAPI-файла: -- Формат: JSON или YAML. -- Версия OpenAPI: 3.0. - -Обязательные секции: -- `openapi`: Версия файла OpenAPI. -- `info`: Общая информация об API. -- `servers`: Данные о серверах для выполнения запросов. -- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. -- `components`: Схемы данных для структур входных и выходных параметров. - -### Генерация кода: -- **Основной объект**: Центральный класс (например, `Pachka`), инициализируемый токеном авторизации. -- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. -- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. -- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. - -### Распространение пакета: -- Сгенерированный код упаковывается для установки через pip или poetry. -- Пакет включает: - - Генератор API-клиента. - - Полную документацию. - - Необходимые метаданные для менеджеров пакетов. - -## Структура проекта - -### Основные компоненты -- **src/generator2/**: - - `bot.py`: Основной класс для работы с API, Метакласс `RequestMethodsCollector` для сбора методов. - - `constants.py`: Константы проекта, Маппинги типов данных, Пути к файлам, HTTP методы. - - `file_writer.py`: Обеспечивает безопасную запись файлов, Создает необходимые директории, Управляет генерацией выходных файлов. - - `yaml_processor.py`: Обрабатывает YAML спецификацию, Генерирует модели запросов и ответов. - - `schema_link_processor.py`: Обрабатывает ссылки на схемы в YAML спецификации. - - `yaml_loader.py`: Загрузка YAML файла спецификации OpenAPI. - -- **requirements.txt**: Список зависимостей генератора с версиями. -- **request_methods_generator.py**: Генерация методов для работы с API на основе OpenAPI спецификации. -- **pachca.py**: Пример использования сгенерированного API клиента. -- **openapi_test.yaml** и **openapi.yaml**: OpenAPI спецификации API, описание эндпоинтов, схем, параметров. -- **src/generator2/models/**: - - `models_response_`: Модели ответов API. - - `models_reqBod_`: Модели запросов API. - -## Установка и использование - -### Инструкция (работать в папке `generator2` при активированном `venv`): -1. Создать файл `.env` в директории `generator2`, с токеном для работы с API пачки. Пример файла: +### 📂 Подготовка OpenAPI-файла: +- Формат: JSON или YAML. +- Версия OpenAPI: 3.0. + +Обязательные секции: +- 🗂️ `openapi`: Версия файла OpenAPI. +- ℹ️ `info`: Общая информация об API. +- 🌍 `servers`: Данные о серверах для выполнения запросов. +- 🛣️ `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. +- 🔗 `components`: Схемы данных для структур входных и выходных параметров. + +### 🔨 Генерация кода: +- 🧩 **Основной объект**: Центральный класс (`Pachka` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. 🔑 +- 🛠️ **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. +- 📋 **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. +- ❌ **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. + +--- + +## 🚀 Установка и использование + +### 🛠️ Инструкция (работать в папке `generator2` при активированном `venv`): +1. ✏️ **Создайте файл `.env`** в директории `generator2`, с токеном для работы с API "Пачка". +Пример файла: ``` TOKEN=ваштокен ``` -2. Создать и активировать виртуальное окружение, установить зависимости: +2. 🐍 **Создайте и активируйте виртуальное окружение, установите зависимости**: - Для Linux/gitBash: ```bash - python3 -m venv venv - source venv/scripts/activate - pip install -r requirements.txt - ``` - - Для Windows cmd: + python3 -m venv venv + source venv/scripts/activate + pip install -r requirements.txt + ``` + - Для Windows cmd: ```bash - python -m venv venv - .\venv\scripts\activate - pip install -r requirements.txt - ``` -3. Запустить генерацию клиента: + python -m venv venv + .\venv\scripts\activate + pip install -r requirements.txt + ``` +3. 🔧 **Запустите генерацию клиента**: ```bash - python -m generator2.generator_starter - ``` -4. Запустить пример запроса: + python -m generator2.generator_starter + ``` +4. 🔍 **Запустите пример запроса**: ```bash - python -m generator2.generator2_full.pachca - ``` - Или перейти в `generator2` и запустить модуль: + python -m generator2.generator2_full.pachca + ``` + Или перейдите в `generator2` и запустите модуль: ```bash - cd generator2 - python -m generator2_full.pachca + cd generator2 + python -m generator2_full.pachca ``` -## Особенности реализации -- Автоматическое определение типов данных. -- Поддержка вложенных моделей. -- Генерация документации на основе описаний из YAML. -- Обработка опциональных полей. -- Поддержка перечислений (Enum). -- Поддержка основных типов HTTP методов (GET, POST, PUT, PATCH, DELETE). -- Автоматическая обработка параметров запроса. - -### Результат генерации -- Типизированные Pydantic модели для запросов и ответов. -- Валидация данных на уровне моделей. -- Поддержка IDE (автодополнение и подсказки типов). - -## Команда проекта +--- -**Студенты Яндекс Практикума, Team 2**: +## 💡 Команда проекта -- Алексей Малков -- Дмитрий Костин -- Александр Малыгин -- Дмитрий Бурмистров +**Студенты Яндекс Практикума, Team 2**: +- Алексей Малков +- Дмитрий Костин +- Александр Малыгин +- Дмитрий Бурмистров -## Дополнительная информация +**📂 Исходный код**: [GitHub Repository](#) +**📄 Документация API**: [Pachca API Documentation](#) -- **Исходный код**: [GitHub Repository](#) -- **Документация API**: [Pachca API Documentation](#) +--- From cb204f73b02ed6a3f33d01eaa60ae36096618fdc Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:38:04 +0300 Subject: [PATCH 208/296] Update README.md --- README.md | 58 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index d3c4c90..7310936 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,68 @@ # Парсер OpenAPI для мессенджера "Пачка" -Библиотека для работы с API мессенджера "Пачка", написанная на Python. 🐍 +### Библиотека для работы с API мессенджера "Пачка", автоматически генерируемая на Python. 🐍 ## 🔖 Цели и задачи проекта Основная цель проекта — создание инструмента для преобразования спецификации OpenAPI в Python-пакет. 📋 Этот пакет предоставляет структурированный и удобный интерфейс для взаимодействия с открытым API мессенджера "Пачка". 🌐 -Проект включает: -- 🚀 **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. -- 📦 **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. +### ✅ Проект включает: +- **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. +- **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. ### 🔧 Основные функции: -- 🌐 **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. -- 📂 **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. -- 🧩 **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. -- 📖 **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. +- **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. +- **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. +- **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. +- **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. --- ## 📚 Используемый стек и технологии ### 🛠️ Языки и фреймворки: -- 🐍 **Python 3.12+**: Основной язык для сгенерированного кода. -- ⚡ **asyncio**: Обеспечивает асинхронный режим работы кода. +- **Python 3.12+**: Основной язык для сгенерированного кода. +- **asyncio**: Обеспечивает асинхронный режим работы кода. ### 📦 Библиотеки: -- 🌐 **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- 🧑‍💻 **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. -- 🗂️ **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- 📄 **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. --- ## 📜 Детали реализации -### 📂 Подготовка OpenAPI-файла: +### 📄 Подготовка OpenAPI-файла: - Формат: JSON или YAML. - Версия OpenAPI: 3.0. -Обязательные секции: -- 🗂️ `openapi`: Версия файла OpenAPI. -- ℹ️ `info`: Общая информация об API. -- 🌍 `servers`: Данные о серверах для выполнения запросов. -- 🛣️ `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. -- 🔗 `components`: Схемы данных для структур входных и выходных параметров. +**Обязательные секции:** +- `openapi`: Версия файла OpenAPI. +- `info`: Общая информация об API. +- `servers`: Данные о серверах для выполнения запросов. +- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. +- `components`: Схемы данных для структур входных и выходных параметров. ### 🔨 Генерация кода: -- 🧩 **Основной объект**: Центральный класс (`Pachka` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. 🔑 -- 🛠️ **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. -- 📋 **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. -- ❌ **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. +- **Основной объект**: Центральный класс (`Pachka` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. +- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. +- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. +- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. --- ## 🚀 Установка и использование ### 🛠️ Инструкция (работать в папке `generator2` при активированном `venv`): -1. ✏️ **Создайте файл `.env`** в директории `generator2`, с токеном для работы с API "Пачка". +1. **Создайте файл `.env`** в директории `generator2`, с токеном для работы с API "Пачка". Пример файла: ``` TOKEN=ваштокен ``` -2. 🐍 **Создайте и активируйте виртуальное окружение, установите зависимости**: +2. **Создайте и активируйте виртуальное окружение, установите зависимости**: - Для Linux/gitBash: ```bash python3 -m venv venv @@ -75,11 +75,11 @@ .\venv\scripts\activate pip install -r requirements.txt ``` -3. 🔧 **Запустите генерацию клиента**: +3. **Запустите генерацию клиента**: ```bash python -m generator2.generator_starter ``` -4. 🔍 **Запустите пример запроса**: +4. **Запустите пример запроса**: ```bash python -m generator2.generator2_full.pachca ``` From 36d45de2e90ecc76f4d6319e89cb46f088890a7f Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:45:40 +0300 Subject: [PATCH 209/296] Update README.md --- README.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/README.md b/README.md index 7310936..0fd1004 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,71 @@ --- +## 📂 Структура проекта + +### 🛠️ Основные компоненты +_src/generator2/_ + +#### 🧩 bot.py +- Основной класс для работы с API +- Метакласс RequestMethodsCollector для сбора методов +- Базовая функциональность для HTTP-запросов +- Форматирование URL и параметров запросов + +#### 🔧 constants.py +- Константы проекта +- Маппинги типов данных +- Пути к файлам +- HTTP методы + +#### 💾 file_writer.py +- Обеспечивает безопасную запись файлов +- Создает необходимые директории +- Управляет генерацией выходных файлов + +#### 📝 yaml_processor.py +- Обрабатывает YAML спецификацию +- Генерирует модели запросов и ответов + - Функция get_all_endpoints для извлечения эндпоинтов из YAML документации + - Функция process_endpoints для обработки эндпоинтов и генерации моделей для requestBody и response + +#### 🌐 request_methods.py +- Содержит асинхронные методы для работы с API +- Импортирует сгенерированные Pydantic модели +- Реализует логику HTTP-запросов + +#### 🔗 schema_link_processor.py +- Обрабатывает ссылки на схемы в YAML спецификации +- Генерирует модели для ссылок на схемы + - unite_schemas для объединения схем + - load_schema для загрузки схемы по ссылке + - new_replace_ref_with_schema для замены ссылок на схемы + +#### 📂 yaml_loader.py +- Загрузка YAML файла спецификации OpenAPI +- Создание глобального объекта YAML_DICT + +#### 📜 requirements.txt +- Список зависимостей генератора с версиями + +#### 🛠️ request_methods_generator.py +- Генерация методов для работы с API на основе OpenAPI спецификации +- Функции форматирования URL, параметров и обработки ответов + +#### 🧪 pachca.py +- Пример использования сгенерированного API клиента +- Тестовые вызовы различных методов API + +#### 📄 openapi_test.yaml и openapi.yaml: +- OpenAPI спецификации API +- Описание эндпоинтов, схем, параметров + +#### 📁 models/ +- models_response_ # Модели ответов API +- models_reqBod_ # Модели запросов API + +--- + ## 📜 Детали реализации ### 📄 Подготовка OpenAPI-файла: From 92ff0c9c5fe756bd8f554e8e5cc9283bd7d234e4 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 11 Jan 2025 18:41:29 +0300 Subject: [PATCH 210/296] more pretty view in example-tests --- src/generator2/README.md | 1 + src/generator2/generator2_full/pachca.py | 126 ++++++++++------------- 2 files changed, 55 insertions(+), 72 deletions(-) diff --git a/src/generator2/README.md b/src/generator2/README.md index b1a052e..3b97970 100644 --- a/src/generator2/README.md +++ b/src/generator2/README.md @@ -30,6 +30,7 @@ python -m generator2.generator_starter ``` python -m generator2.generator2_full.pachca ``` + ИЛИ перейти в generator2 ```cd generator2``` и запустить модуль ``` diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 5dd53ae..f111105 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -4,53 +4,45 @@ from dotenv import load_dotenv from .bot import Bot -from .models.models_reqBod_putStatus import Putstatus from .models.models_reqBod_createChat import Createchat +from .models.models_reqBod_createMessage import Createmessage, Message from .models.models_reqBod_createTask import Createtask -from .models.models_reqBod_postMessageReactions import Postmessagereactions from .models.models_reqBod_editMessage import Editmessage -from .models.models_reqBod_postTagsToChats import Posttagstochats -from .models.models_reqBod_createMessage import Createmessage, Message from .models.models_reqBod_postMembersToChats import Postmemberstochats +from .models.models_reqBod_postMessageReactions import Postmessagereactions +from .models.models_reqBod_putStatus import Putstatus load_dotenv() if __name__ == '__main__': - - print(id(Bot)) - print(Bot) pachca = Bot(token=f'Bearer {os.environ.get("TOKEN", "LOOKUP FAILED!")}') - print(pachca.token) - print(hasattr(pachca, 'get_common_methods')) - message_test = Createmessage(message=Message( entity_type="discussion", entity_id=17579010, - content="Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье)", + content=("Вчера мы продали 756 футболок " + "(что на 10% больше, чем в прошлое воскресенье)"), )) - #print(message_test.model_dump()) async def run_pachca(): - print(await pachca.get_employee(id=515190)) - print(await pachca.get_employees()) - print(await pachca.get_chats(per=2)) + print('-> get_employee', await pachca.get_employee(id=515190), sep='\n',end='\n'+ '*'*60 + '\n') + print('-> get_employees', await pachca.get_employees(), sep='\n',end='\n'+ '*'*60 + '\n') + print('-> get_chats', await pachca.get_chats(per=2), sep='\n',end='\n'+ '*'*60 + '\n') message = await pachca.create_message(data=message_test) - print(message) - print(await pachca.get_common_methods()) #Возвращает ошибку, нужно прописать обработку если (parameters.query и parameters.required) - + print(message, sep='\n',end='\n'+ '*'*60 + '\n') + print(await pachca.get_common_methods(), sep='\n',end='\n'+ '*'*60 + '\n') # Создание беседы. created_chat = await pachca.create_chat( data=Createchat( chat={ 'name': 'Тестовая беседа 31', 'channel': False, - 'public': True - } - ) + 'public': True, + }, + ), ) print('create_chat', created_chat, '\n','*'*60) - # Получение всех бесед данного рабочего пространства (РП токена) + # Получение всех бесед данного рабочего пространства all_chats = await pachca.get_chats() print('get_chats', all_chats, '\n','*'*60) @@ -62,11 +54,15 @@ async def run_pachca(): response_post_members = await pachca.post_members_to_chats( id=chat.data.id, data=Postmemberstochats( - member_ids=[515190], - silent=False - ) + member_ids=[518863], + silent=False, + ), ) - print('post_members_to_chats', response_post_members, '\n','*'*60) + print('post_members_to_chats', response_post_members, sep='\n',end='\n'+ '*'*60 + '\n') + + # Получение всех бесед данного рабочего пространства (на одну больше) + all_chats = await pachca.get_chats() + print('get_chats /', all_chats, '\n','*'*60) # Создание нового сообщения в беседе. response_create_message = await pachca.create_message( @@ -74,29 +70,18 @@ async def run_pachca(): message={ 'content': f'Запощеное сообщение в беседу {chat.data.id}', 'entity_type': 'discussion', - 'entity_id': chat.data.id - } - ) + 'entity_id': chat.data.id, + }, + ), ) print('create_message', response_create_message, '\n','*'*60) - # Добавление тегов чату, пока неот способа создавать теги. - # response = await pachca.post_tags_to_chats( - # id=17519775, - # data=Posttagstochats( - # group_tag_ids=[1, 2, 3] - # ) - # ) - # Получение списка тегов print(await pachca.get_tags()) - # Получение всех сотрудников с тегом с id. - # print(await pachca.get_tags_employees() - # Создание треда к конкретному сообщению с id. response_create_thread = await pachca.create_thread( - id=response_create_message.data.id + id=response_create_message.data.id, ) print('create_thread', response_create_thread, '\n','*'*60) @@ -104,23 +89,25 @@ async def run_pachca(): response_create_message_in_thread = await pachca.create_message( data=Createmessage( message={ - 'content': f'Новое сообщение в тред {response_create_thread.data.id}', + 'content': f'Новое сообщение в тред { + response_create_thread.data.id}', 'entity_type': 'thread', - 'entity_id': response_create_thread.data.id - } - ) + 'entity_id': response_create_thread.data.id, + }, + ), ) - print('create_message_in_thread', response_create_message_in_thread, '\n','*'*60) + print('create_message_in_thread', + response_create_message_in_thread, '\n','*'*60) # Получение списка всех сообщений конкретного треда или беседы с пагинацией response_list_messages = await pachca.get_list_message( - chat_id=response_create_thread.data.chat_id, per=10, page=1 + chat_id=response_create_thread.data.chat_id, per=10, page=1, ) print('get_list_message', response_list_messages, '\n','*'*60) # Получение конкретного сообщения по id response_get_message = await pachca.get_message( - id=response_create_message_in_thread.data.id + id=response_create_message_in_thread.data.id, ) print('get_message', response_get_message, '\n','*'*60) @@ -130,19 +117,19 @@ async def run_pachca(): data=Editmessage(message={ 'content': ('РЕДАКТИРОВАНИЕ СООБЩЕНИЯ ' f'{response_create_message_in_thread.data.id} ' - 'ЧЕРЕЗ АПИ СОВЕРШЕНО УСПЕШНО') - }) + 'ЧЕРЕЗ АПИ СОВЕРШЕНО УСПЕШНО'), + }), ) print('edit_message', response_edit_message, '\n','*'*60) # Добавление реакции к сообщению с id response_add_reaction = await pachca.post_message_reactions( id=response_edit_message.data.id, - data=Postmessagereactions(code='👍') + data=Postmessagereactions(code='👍'), ) response_add_reaction = await pachca.post_message_reactions( id=response_edit_message.data.id, - data=Postmessagereactions(code='😱') + data=Postmessagereactions(code='😱'), ) print('post_message_reactions', response_add_reaction, '\n','*'*60) @@ -155,9 +142,10 @@ async def run_pachca(): # Удаение конкретной реакции у конкретного сообщения. response_delete_reaction = await pachca.delete_message_reactions( id=response_edit_message.data.id, - code='😱' + code='😱', ) - print('delete_message_reactions', response_delete_reaction, '\n','*'*60) + print('delete_message_reactions', + response_delete_reaction, '\n','*'*60) # Создание напоминания response_create_task = await pachca.create_task( @@ -166,17 +154,17 @@ async def run_pachca(): 'kind': 'reminder', 'content': 'дата в прошлом', 'priority': 3, - 'due_at': '2025-12-24T18:00:29.000Z' - } - ) + 'due_at': '2025-12-24T18:00:29.000Z', + }, + ), ) print('create_task', response_create_task, '\n','*'*60) - # Метод для того чтобы покинуть конкретный чат (беседу) - response = await pachca.leave_chat( - id=created_chat.data.id - ) - print(response) + # # Метод для того чтобы покинуть конкретный чат (беседу) + # response = await pachca.leave_chat( + # id=created_chat.data.id, + # ) + # print(response) # Получить список всех сотрудников рабочего пространства. response_get_users = await pachca.get_employees() @@ -185,7 +173,7 @@ async def run_pachca(): # Получить конкретного сотрудника рабочего простанства. response_get_user = await pachca.get_employee( - response_get_users.data[0].id + response_get_users.data[0].id, ) print('get_employee', response_get_user, '\n','*'*60) @@ -195,9 +183,9 @@ async def run_pachca(): status={ 'emoji': '😱', 'expires_at': '2025-12-24T17:47:25.000Z', - 'title': 'Статус из клиента АПИ' - } - ) + 'title': 'Статус из клиента АПИ', + }, + ), ) print('put_status', response_put_status, '\n','*'*60) @@ -209,10 +197,4 @@ async def run_pachca(): response_del_status = await pachca.del_status() print('del_status', response_del_status, '\n','*'*60) - asyncio.run(run_pachca()) - - # print(type(pachca)) - # print(pachca.__class__) - # print(pachca.__class__.__class__) - # print(pachca.__class__.__class__.__class__) \ No newline at end of file From 2a97d2e5644c942d500b767fd1d67bd29a547bcf Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sat, 11 Jan 2025 19:31:09 +0300 Subject: [PATCH 211/296] logging for client and pachca.py tests --- src/generator2/generator2_full/constants.py | 6 ++ .../generator2_full/logger_setup.py | 19 ++++++ src/generator2/generator2_full/pachca.py | 66 ++++++++++--------- src/generator2/services/logger_setup.py | 1 - src/generator2/yaml_processor.py | 30 ++++++--- 5 files changed, 80 insertions(+), 42 deletions(-) create mode 100644 src/generator2/generator2_full/logger_setup.py diff --git a/src/generator2/generator2_full/constants.py b/src/generator2/generator2_full/constants.py index 6e2eb55..7c8a0f6 100644 --- a/src/generator2/generator2_full/constants.py +++ b/src/generator2/generator2_full/constants.py @@ -1,3 +1,9 @@ +# Client constants URL = 'https://api.pachca.com/api/shared/v1' PARAM_NAME_SORT = 'sort' PARAM_NAME_SORT_FIELD = 'sort_field' + +# Logger constants +LOG_FILE_NAME = 'pachca_log.log' +MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB +BACKUP_COUNT = 3 diff --git a/src/generator2/generator2_full/logger_setup.py b/src/generator2/generator2_full/logger_setup.py new file mode 100644 index 0000000..431ab61 --- /dev/null +++ b/src/generator2/generator2_full/logger_setup.py @@ -0,0 +1,19 @@ +import logging +from logging.handlers import RotatingFileHandler + +from .constants import LOG_FILE_NAME, MAX_FILE_SIZE, BACKUP_COUNT + + +def setup_logging(logger_name: str) -> logging.Logger: + logger = logging.getLogger(logger_name) + logger.setLevel(logging.DEBUG) + file_handler = RotatingFileHandler( + LOG_FILE_NAME, maxBytes=MAX_FILE_SIZE, + backupCount=BACKUP_COUNT, + encoding='utf-8' + ) + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') + file_handler.setFormatter(formatter) + logger.addHandler(file_handler) + return logger diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index f111105..051bc3f 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -4,6 +4,7 @@ from dotenv import load_dotenv from .bot import Bot +from .logger_setup import setup_logging from .models.models_reqBod_createChat import Createchat from .models.models_reqBod_createMessage import Createmessage, Message from .models.models_reqBod_createTask import Createtask @@ -14,6 +15,8 @@ load_dotenv() +logger = setup_logging('pachca_log') + if __name__ == '__main__': pachca = Bot(token=f'Bearer {os.environ.get("TOKEN", "LOOKUP FAILED!")}') @@ -24,12 +27,13 @@ "(что на 10% больше, чем в прошлое воскресенье)"), )) async def run_pachca(): - print('-> get_employee', await pachca.get_employee(id=515190), sep='\n',end='\n'+ '*'*60 + '\n') - print('-> get_employees', await pachca.get_employees(), sep='\n',end='\n'+ '*'*60 + '\n') - print('-> get_chats', await pachca.get_chats(per=2), sep='\n',end='\n'+ '*'*60 + '\n') - message = await pachca.create_message(data=message_test) - print(message, sep='\n',end='\n'+ '*'*60 + '\n') - print(await pachca.get_common_methods(), sep='\n',end='\n'+ '*'*60 + '\n') + # logger.debug(f'get_employee', await pachca.get_employee(id=515190), sep='\n',end='\n'+ '*'*60 + '\n') + # logger.debug(f'get_employees', await pachca.get_employees(), sep='\n',end='\n'+ '*'*60 + '\n') + # logger.debug(f'get_chats', await pachca.get_chats(per=2), sep='\n',end='\n'+ '*'*60 + '\n') + # message = await pachca.create_message(data=message_test) + # logger.debug(message, sep='\n',end='\n'+ '*'*60 + '\n') + # Получение common methods + logger.debug(f'get_common_methods: {await pachca.get_common_methods()}') # Создание беседы. created_chat = await pachca.create_chat( data=Createchat( @@ -40,15 +44,15 @@ async def run_pachca(): }, ), ) - print('create_chat', created_chat, '\n','*'*60) + logger.debug(f'create_chat: {created_chat}') # Получение всех бесед данного рабочего пространства all_chats = await pachca.get_chats() - print('get_chats', all_chats, '\n','*'*60) + logger.debug(f'get_chats: {all_chats}') # Получение конкретной беседы по id chat = await pachca.get_chat(created_chat.data.id) - print('get_chat', chat, '\n','*'*60) + logger.debug(f'get_chat: {chat}') # Подключение пользователей к беседе. response_post_members = await pachca.post_members_to_chats( @@ -58,11 +62,11 @@ async def run_pachca(): silent=False, ), ) - print('post_members_to_chats', response_post_members, sep='\n',end='\n'+ '*'*60 + '\n') + logger.debug(f'post_members_to_chats: {response_post_members}') # Получение всех бесед данного рабочего пространства (на одну больше) all_chats = await pachca.get_chats() - print('get_chats /', all_chats, '\n','*'*60) + logger.debug(f'get_chats: {all_chats}') # Создание нового сообщения в беседе. response_create_message = await pachca.create_message( @@ -74,42 +78,43 @@ async def run_pachca(): }, ), ) - print('create_message', response_create_message, '\n','*'*60) + logger.debug(f'create_message: {response_create_message}') # Получение списка тегов - print(await pachca.get_tags()) + logger.debug(f'get_tags: {await pachca.get_tags()}') # Создание треда к конкретному сообщению с id. response_create_thread = await pachca.create_thread( id=response_create_message.data.id, ) - print('create_thread', response_create_thread, '\n','*'*60) + logger.debug(f'create_thread: {response_create_thread}') # Создание комментария в треде другого сообщения response_create_message_in_thread = await pachca.create_message( data=Createmessage( message={ - 'content': f'Новое сообщение в тред { - response_create_thread.data.id}', + 'content': ( + 'Новое сообщение в тред' + f'{response_create_thread.data.id}' + ), 'entity_type': 'thread', 'entity_id': response_create_thread.data.id, }, ), ) - print('create_message_in_thread', - response_create_message_in_thread, '\n','*'*60) + logger.debug(f'create_message_in_thread: {response_create_message_in_thread}') # Получение списка всех сообщений конкретного треда или беседы с пагинацией response_list_messages = await pachca.get_list_message( chat_id=response_create_thread.data.chat_id, per=10, page=1, ) - print('get_list_message', response_list_messages, '\n','*'*60) + logger.debug(f'get_list_message: {response_list_messages}') # Получение конкретного сообщения по id response_get_message = await pachca.get_message( id=response_create_message_in_thread.data.id, ) - print('get_message', response_get_message, '\n','*'*60) + logger.debug(f'get_message: {response_get_message}') # Редактирование конкретного сообщения по его id response_edit_message = await pachca.edit_message( @@ -120,7 +125,7 @@ async def run_pachca(): 'ЧЕРЕЗ АПИ СОВЕРШЕНО УСПЕШНО'), }), ) - print('edit_message', response_edit_message, '\n','*'*60) + logger.debug(f'edit_message: {response_edit_message}') # Добавление реакции к сообщению с id response_add_reaction = await pachca.post_message_reactions( @@ -131,21 +136,20 @@ async def run_pachca(): id=response_edit_message.data.id, data=Postmessagereactions(code='😱'), ) - print('post_message_reactions', response_add_reaction, '\n','*'*60) + logger.debug(f'post_message_reactions: {response_add_reaction}') # Получение списка всех реакций конкретного сообщения. response_message_reactions = await pachca.get_message_reactions( id=response_edit_message.data.id, ) - print('get_message_reactions', response_message_reactions, '\n','*'*60) + logger.debug(f'get_message_reactions: {response_message_reactions}') # Удаение конкретной реакции у конкретного сообщения. response_delete_reaction = await pachca.delete_message_reactions( id=response_edit_message.data.id, code='😱', ) - print('delete_message_reactions', - response_delete_reaction, '\n','*'*60) + logger.debug(f'delete_message_reactions: {response_delete_reaction}') # Создание напоминания response_create_task = await pachca.create_task( @@ -158,7 +162,7 @@ async def run_pachca(): }, ), ) - print('create_task', response_create_task, '\n','*'*60) + logger.debug(f'create_task: {response_create_task}') # # Метод для того чтобы покинуть конкретный чат (беседу) # response = await pachca.leave_chat( @@ -169,13 +173,13 @@ async def run_pachca(): # Получить список всех сотрудников рабочего пространства. response_get_users = await pachca.get_employees() print('get_employees', response_get_users, '\n','*'*60) - print(response_get_users.data[0].id) + logger.debug(f'One user from list: {response_get_users.data[0].id}') # Получить конкретного сотрудника рабочего простанства. response_get_user = await pachca.get_employee( response_get_users.data[0].id, ) - print('get_employee', response_get_user, '\n','*'*60) + logger.debug('get_employee: {response_get_user}') # Добавить статус текущему пользователю, обладателю токена. response_put_status = await pachca.put_status( @@ -187,14 +191,14 @@ async def run_pachca(): }, ), ) - print('put_status', response_put_status, '\n','*'*60) + logger.debug(f'put_status: {response_put_status}') # Получить статус текущего пользователя, обладателя токена. response_get_status = await pachca.get_status() - print('get_status', response_get_status, '\n','*'*60) + logger.debug(f'get_status: {response_get_status}') # Удалить статус текущему пользователю, обладателю токена. response_del_status = await pachca.del_status() - print('del_status', response_del_status, '\n','*'*60) + logger.debug(f'del_status: {response_del_status}') asyncio.run(run_pachca()) diff --git a/src/generator2/services/logger_setup.py b/src/generator2/services/logger_setup.py index 3b24f1e..36c8a59 100644 --- a/src/generator2/services/logger_setup.py +++ b/src/generator2/services/logger_setup.py @@ -5,7 +5,6 @@ def setup_logging(logger_name: str) -> logging.Logger: logger = logging.getLogger(logger_name) - logger logger.setLevel(logging.DEBUG) file_handler = logging.FileHandler(LOG_FILE_NAME, encoding='utf-8') formatter = logging.Formatter( diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index e4b58dd..917f5f8 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -13,6 +13,25 @@ logger = setup_logging('yaml_processor') +def create_constants_for_client(yaml_dict: dict) -> str: + """Записывает файл констант для клиента.""" + write_to_file( + 'constants', + ( + "# Client constants\n" + f"URL = '{yaml_dict['servers'][0]['url']}'\n" + "PARAM_NAME_SORT = 'sort'\n" + "PARAM_NAME_SORT_FIELD = 'sort_field'\n\n" + "# Logger constants\n" + "LOG_FILE_NAME = 'pachca_log.log'\n" + "MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB\n" + "BACKUP_COUNT = 3\n" + ), + folder_name='', + open_file_mode='w' + ) + + def get_all_endpoints(yaml_dict: dict): """Получает все эндпоинты из path документации.""" endpoints = yaml_dict.get('paths') @@ -33,16 +52,7 @@ def process_endpoints() -> tuple[list, list]: Проходит по каждому эндпоинту в openapi файле и генерирует модели для каждой схемы в requestBody и resopnse. """ - write_to_file( - 'constants', - ( - f"URL = '{YAML_DICT['servers'][0]['url']}'\n" - "PARAM_NAME_SORT = 'sort'\n" - "PARAM_NAME_SORT_FIELD = 'sort_field'\n" - ), - folder_name='', - open_file_mode='w' - ) + create_constants_for_client(YAML_DICT) body: dict for endpoint, method, body in get_all_endpoints(YAML_DICT): logger.debug(f'Working on: {endpoint}, {method}') From 60492bba15c3e67b867fcf3cbbab2db9b612a027 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 11 Jan 2025 20:44:37 +0300 Subject: [PATCH 212/296] fixed changes --- src/generator2/generator2_full/logger_setup.py | 2 +- src/generator2/generator2_full/pachca.py | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/generator2/generator2_full/logger_setup.py b/src/generator2/generator2_full/logger_setup.py index 431ab61..814f142 100644 --- a/src/generator2/generator2_full/logger_setup.py +++ b/src/generator2/generator2_full/logger_setup.py @@ -1,7 +1,7 @@ import logging from logging.handlers import RotatingFileHandler -from .constants import LOG_FILE_NAME, MAX_FILE_SIZE, BACKUP_COUNT +from .constants import BACKUP_COUNT, LOG_FILE_NAME, MAX_FILE_SIZE def setup_logging(logger_name: str) -> logging.Logger: diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 051bc3f..546ab47 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -164,22 +164,14 @@ async def run_pachca(): ) logger.debug(f'create_task: {response_create_task}') - # # Метод для того чтобы покинуть конкретный чат (беседу) - # response = await pachca.leave_chat( - # id=created_chat.data.id, - # ) - # print(response) - - # Получить список всех сотрудников рабочего пространства. response_get_users = await pachca.get_employees() - print('get_employees', response_get_users, '\n','*'*60) logger.debug(f'One user from list: {response_get_users.data[0].id}') # Получить конкретного сотрудника рабочего простанства. response_get_user = await pachca.get_employee( response_get_users.data[0].id, ) - logger.debug('get_employee: {response_get_user}') + logger.debug(f'get_employee: {response_get_user}') # Добавить статус текущему пользователю, обладателю токена. response_put_status = await pachca.put_status( @@ -200,5 +192,6 @@ async def run_pachca(): # Удалить статус текущему пользователю, обладателю токена. response_del_status = await pachca.del_status() logger.debug(f'del_status: {response_del_status}') + logger.debug('*' * 60) asyncio.run(run_pachca()) From 00e468988df8f1598b21fa3048e8d26e0218ddc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Sat, 11 Jan 2025 21:35:11 +0300 Subject: [PATCH 213/296] bugfix getCommonMethods, createTask, putStatus --- src/generator1/openapi_new.yaml | 68 +++++++++++++++++++++++++++++---- src/generator1/pachca.py | 9 ++++- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/generator1/openapi_new.yaml b/src/generator1/openapi_new.yaml index 5b209d4..5023e30 100644 --- a/src/generator1/openapi_new.yaml +++ b/src/generator1/openapi_new.yaml @@ -52,9 +52,6 @@ paths: required: true schema: type: string - enum: - - User - - Task responses: '200': description: Успешный запрос @@ -126,7 +123,7 @@ paths: schema: $ref: '#/components/schemas/DirectResponse' responses: - '204': + '201': description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: @@ -247,9 +244,9 @@ paths: type: object properties: status: - $ref: '#/components/schemas/Status' + $ref: '#/components/schemas/QueryStatus' responses: - '201': + '200': description: Объект создан content: application/json: @@ -1379,7 +1376,7 @@ paths: schema: $ref: '#/components/schemas/CodeReaction' responses: - "204": + "201": description: Успешное выполнение запроса, тело ответа отсутствует. '400': description: Пояснения ошибки @@ -1589,7 +1586,41 @@ paths: type: object properties: task: - $ref: '#/components/schemas/BaseTask' + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля responses: '201': description: Напоминание успешно создано @@ -1853,6 +1884,27 @@ components: nullable: true description: | Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + type: object + properties: + status: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + nullable: true CommonMethods: title: Common Methods type: object diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 828df83..b0d75f9 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -66,6 +66,11 @@ CreateTaskBody, ) +from pachca_api_open_api_3_0_client.models import ( + CreateTaskBodyTask, QueryStatusStatus +) + + ''' from pachca_api_open_api_3_0_client.models.edit_messages import EditMessages from pachca_api_open_api_3_0_client.models.edit_message_body import ( @@ -185,7 +190,7 @@ async def main() -> None: print('*' * 60) # подготовка запроса на создание напоминания --> - create_body_task = CreateTaskBody( + create_body_task = CreateTaskBodyTask( kind='call', content='Звонок другу', due_at=datetime.datetime.now(), @@ -208,7 +213,7 @@ async def main() -> None: print('*' * 60) # подготовка запроса на добавление статуса --> - query_status = PutStatusBody( + query_status = QueryStatusStatus( emoji='😭', title='Я не плачу это просто слезы', expires_at=None From 1a30c5ed5b3a3013e46825a1a4a7a4af3dc78ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Sat, 11 Jan 2025 23:49:25 +0300 Subject: [PATCH 214/296] bugfix EditMessageResponse --- src/generator1/openapi_new.yaml | 5 +---- src/generator1/pachca.py | 9 ++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/generator1/openapi_new.yaml b/src/generator1/openapi_new.yaml index 5023e30..0f96d4a 100644 --- a/src/generator1/openapi_new.yaml +++ b/src/generator1/openapi_new.yaml @@ -1312,10 +1312,7 @@ paths: type: object properties: data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' + $ref: '#/components/schemas/Message' '400': description: Пояснения ошибки content: diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index b0d75f9..bb15465 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -67,7 +67,7 @@ ) from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, QueryStatusStatus + CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody ) @@ -147,9 +147,8 @@ async def main() -> None: pachca.getMessage(id=message_response.data.id)) ) print('*' * 60) - ''' - Запрос проходит успешно, но в yaml схема ответа прописана не корректно. - Поэтому успешный ответ приводит AttributeError. + + # подготовка запроса на редактирование сообщения --> edit_meassage = EditMessages(content='NOT SUPER PUPER') edit_message_body = EditMessageBody(message=edit_meassage) @@ -161,7 +160,7 @@ async def main() -> None: ) ) print('*' * 60) - ''' + # подготовка запроса на добавление реакции к сообщению --> post_reactions = CodeReaction(code='😭') From 292638d2d87f50fe77d7082cab152c3c463862f1 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 00:10:28 +0300 Subject: [PATCH 215/296] delete yaml-test --- .../models/models_reqBod_createMessage.py | 6 +- .../models/models_reqBod_createTask.py | 4 +- .../models/models_reqBod_editMessage.py | 4 +- .../models_response_createMessagepost201.py | 6 +- .../models_response_createTaskpost201.py | 6 +- .../models_response_editMessageput200.py | 6 +- .../models_response_getCommonMethodsget200.py | 4 +- .../models_response_getEmployeeget200.py | 8 +- .../models_response_getEmployeesget200.py | 8 +- .../models_response_getListMessageget200.py | 6 +- .../models_response_getMessageget200.py | 6 +- .../models_response_getTagsEmployeesget200.py | 8 +- src/generator2/openapi_test.yaml | 2364 ----------------- 13 files changed, 36 insertions(+), 2400 deletions(-) delete mode 100644 src/generator2/openapi_test.yaml diff --git a/src/generator2/generator2_full/models/models_reqBod_createMessage.py b/src/generator2/generator2_full/models/models_reqBod_createMessage.py index bf30d10..a6280ed 100644 --- a/src/generator2/generator2_full/models/models_reqBod_createMessage.py +++ b/src/generator2/generator2_full/models/models_reqBod_createMessage.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ class Buttons(BaseModel): data: Optional[str] = Field(None, description="No docstring provided") -class enum_file_type(str, Enum): +class enum_file_type(StrEnum): file = "file" image = "image" @@ -30,7 +30,7 @@ class Files(BaseModel): ) -class enum_entity_type(str, Enum): +class enum_entity_type(StrEnum): discussion = "discussion" user = "user" thread = "thread" diff --git a/src/generator2/generator2_full/models/models_reqBod_createTask.py b/src/generator2/generator2_full/models/models_reqBod_createTask.py index d5a84ba..ce503e3 100644 --- a/src/generator2/generator2_full/models/models_reqBod_createTask.py +++ b/src/generator2/generator2_full/models/models_reqBod_createTask.py @@ -1,4 +1,4 @@ -from enum import Enum, IntEnum +from enum import IntEnum, StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -9,7 +9,7 @@ class Custom_properties(BaseModel): value: Optional[str] = Field(None, description="Значение поля") -class enum_kind(str, Enum): +class enum_kind(StrEnum): call = "call" meeting = "meeting" reminder = "reminder" diff --git a/src/generator2/generator2_full/models/models_reqBod_editMessage.py b/src/generator2/generator2_full/models/models_reqBod_editMessage.py index aebff74..8db9faf 100644 --- a/src/generator2/generator2_full/models/models_reqBod_editMessage.py +++ b/src/generator2/generator2_full/models/models_reqBod_editMessage.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ class Buttons(BaseModel): data: Optional[str] = Field(None, description="No docstring provided") -class enum_file_type(str, Enum): +class enum_file_type(StrEnum): file = "file" image = "image" diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost201.py b/src/generator2/generator2_full/models/models_response_createMessagepost201.py index 4706f3b..a7da269 100644 --- a/src/generator2/generator2_full/models/models_response_createMessagepost201.py +++ b/src/generator2/generator2_full/models/models_response_createMessagepost201.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ class Buttons(BaseModel): data: Optional[str] = Field(None, description="No docstring provided") -class enum_file_type(str, Enum): +class enum_file_type(StrEnum): file = "file" image = "image" @@ -66,7 +66,7 @@ class Forwarding(BaseModel): ) -class enum_entity_type(str, Enum): +class enum_entity_type(StrEnum): discussion = "discussion" user = "user" thread = "thread" diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost201.py b/src/generator2/generator2_full/models/models_response_createTaskpost201.py index 937feb5..749ca91 100644 --- a/src/generator2/generator2_full/models/models_response_createTaskpost201.py +++ b/src/generator2/generator2_full/models/models_response_createTaskpost201.py @@ -1,10 +1,10 @@ -from enum import Enum, IntEnum +from enum import IntEnum, StrEnum from typing import List, Optional from pydantic import BaseModel, Field -class enum_data_type(str, Enum): +class enum_data_type(StrEnum): string = "string" number = "number" date = "date" @@ -20,7 +20,7 @@ class Custom_properties(BaseModel): ) -class enum_kind(str, Enum): +class enum_kind(StrEnum): call = "call" meeting = "meeting" reminder = "reminder" diff --git a/src/generator2/generator2_full/models/models_response_editMessageput200.py b/src/generator2/generator2_full/models/models_response_editMessageput200.py index 12d6039..2daa577 100644 --- a/src/generator2/generator2_full/models/models_response_editMessageput200.py +++ b/src/generator2/generator2_full/models/models_response_editMessageput200.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ class Buttons(BaseModel): data: Optional[str] = Field(None, description="No docstring provided") -class enum_file_type(str, Enum): +class enum_file_type(StrEnum): file = "file" image = "image" @@ -66,7 +66,7 @@ class Forwarding(BaseModel): ) -class enum_entity_type(str, Enum): +class enum_entity_type(StrEnum): discussion = "discussion" user = "user" thread = "thread" diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py index 5f37b84..9c132b3 100644 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py +++ b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py @@ -1,10 +1,10 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field -class enum_data_type(str, Enum): +class enum_data_type(StrEnum): string = "string" number = "number" date = "date" diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py index 74ca371..a798652 100644 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py +++ b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py @@ -1,10 +1,10 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field -class enum_data_type(str, Enum): +class enum_data_type(StrEnum): string = "string" number = "number" date = "date" @@ -29,13 +29,13 @@ class User_status(BaseModel): ) -class enum_role(str, Enum): +class enum_role(StrEnum): admin = "admin" user = "user" multi_guest = "multi_guest" -class enum_invite_status(str, Enum): +class enum_invite_status(StrEnum): confirmed = "confirmed" sent = "sent" diff --git a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py index b43067b..6f24174 100644 --- a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py +++ b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py @@ -1,10 +1,10 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field -class enum_data_type(str, Enum): +class enum_data_type(StrEnum): string = "string" number = "number" date = "date" @@ -29,13 +29,13 @@ class User_status(BaseModel): ) -class enum_role(str, Enum): +class enum_role(StrEnum): admin = "admin" user = "user" multi_guest = "multi_guest" -class enum_invite_status(str, Enum): +class enum_invite_status(StrEnum): confirmed = "confirmed" sent = "sent" diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget200.py b/src/generator2/generator2_full/models/models_response_getListMessageget200.py index bc74a85..c187528 100644 --- a/src/generator2/generator2_full/models/models_response_getListMessageget200.py +++ b/src/generator2/generator2_full/models/models_response_getListMessageget200.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ class Buttons(BaseModel): data: Optional[str] = Field(None, description="No docstring provided") -class enum_file_type(str, Enum): +class enum_file_type(StrEnum): file = "file" image = "image" @@ -66,7 +66,7 @@ class Forwarding(BaseModel): ) -class enum_entity_type(str, Enum): +class enum_entity_type(StrEnum): discussion = "discussion" user = "user" thread = "thread" diff --git a/src/generator2/generator2_full/models/models_response_getMessageget200.py b/src/generator2/generator2_full/models/models_response_getMessageget200.py index ea3007e..92d3d71 100644 --- a/src/generator2/generator2_full/models/models_response_getMessageget200.py +++ b/src/generator2/generator2_full/models/models_response_getMessageget200.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ class Buttons(BaseModel): data: Optional[str] = Field(None, description="No docstring provided") -class enum_file_type(str, Enum): +class enum_file_type(StrEnum): file = "file" image = "image" @@ -66,7 +66,7 @@ class Forwarding(BaseModel): ) -class enum_entity_type(str, Enum): +class enum_entity_type(StrEnum): discussion = "discussion" user = "user" thread = "thread" diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py index 53fe41c..d835b3a 100644 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py +++ b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py @@ -1,10 +1,10 @@ -from enum import Enum +from enum import StrEnum from typing import List, Optional from pydantic import BaseModel, Field -class enum_data_type(str, Enum): +class enum_data_type(StrEnum): string = "string" number = "number" date = "date" @@ -20,13 +20,13 @@ class Custom_properties(BaseModel): value: Optional[str] = Field(None, description="Значение") -class enum_role(str, Enum): +class enum_role(StrEnum): admin = "admin" user = "user" multi_guest = "multi_guest" -class enum_invite_status(str, Enum): +class enum_invite_status(StrEnum): confirmed = "confirmed" sent = "sent" diff --git a/src/generator2/openapi_test.yaml b/src/generator2/openapi_test.yaml deleted file mode 100644 index c616c9f..0000000 --- a/src/generator2/openapi_test.yaml +++ /dev/null @@ -1,2364 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - enum: - - User - - Task - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - - $ref: '#/components/parameters/queryParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/Status' - responses: - '201': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - $ref: '#/components/parameters/sortParameter' - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - - $ref: '#/components/parameters/availabilityParameter' - - $ref: '#/components/parameters/last_message_at_afterParameter' - - $ref: '#/components/parameters/last_message_at_beforeParameter' - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '201': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '201': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '200': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '200': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - $ref: '#/components/parameters/chatParameter' - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - $ref: '#/components/parameters/reactionParameter' - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - $ref: '#/components/schemas/Task' - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - parameters: - perParameter50: - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - perParameter25: - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - pageParameter: - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - queryParameter: - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - chatParameter: - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - sortParameter: - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - availabilityParameter: - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - last_message_at_afterParameter: - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - last_message_at_beforeParameter: - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - reactionParameter: - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: array - items: - title: Error - type: object - properties: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - nullable: true - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: array - items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - CreateEditFiles: - title: Create&Edit Files - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: array - items: - type: object - properties: - size: - title: Size - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: array - items: - type: object - properties: - id: - title: Id - type: integer - url: - title: Url - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - allOf: - - $ref: '#/components/schemas/Files' - title: files - thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - title: Custom Properties - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: array - items: - type: object - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] \ No newline at end of file From f513038cecb0f91e8b511b257395605dc1c38895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=9A=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B0=D0=BA?= Date: Sun, 12 Jan 2025 00:29:19 +0300 Subject: [PATCH 216/296] bugfix delstatus --- src/generator1/pachca.py | 5 ++--- src/generator1/templates/endpoint_module.py.jinja | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index bb15465..4444079 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -226,12 +226,11 @@ async def main() -> None: print(await asyncio.create_task(pachca.getStatus())) print('*' * 60) - ''' - В client.py отсутствует метод delStatus + + # запрос на удаление статуса print(await asyncio.create_task(pachca.delStatus())) print('*' * 60) - ''' # запрос на получение тегов сотрудников print(await asyncio.create_task(pachca.getTags())) diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index 8ad250b..f8c8e0e 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -99,7 +99,6 @@ def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> Respo ) -{% if parsed_responses %} async def {{ endpoint.name }}(self, {{ arguments(endpoint) | indent(4) }} ) -> Optional[{{ return_string }}]: @@ -115,4 +114,4 @@ async def {{ endpoint.name }}(self, return self._build_response_{{ endpoint.name }}( response=response).parsed -{% endif %} + From 945eb4c407bc62a57c972995d99989befe60a83e Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sun, 12 Jan 2025 01:17:20 +0300 Subject: [PATCH 217/296] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit описал 2 типа используемых библиотек --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fd1004..4d4acc2 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,18 @@ - **Python 3.12+**: Основной язык для сгенерированного кода. - **asyncio**: Обеспечивает асинхронный режим работы кода. -### 📦 Библиотеки: +### 📦 Библиотеки (gen_v1): - **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. - **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. - **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. - **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +### 📦 Библиотеки (gen_v2): +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. + --- ## 📂 Структура проекта From 544084503414d459da168eb81d0ed099f2f5df34 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Sun, 12 Jan 2025 12:23:20 +0500 Subject: [PATCH 218/296] library_generator2_ver2 --- src/builder/Makefile | 15 + src/builder/Pipfile | 56 ++ src/builder/Pipfile.lock | 926 ++++++++++++++++++ src/builder/README.md | 23 +- src/builder/requirements.txt | 45 + src/builder/setup_generator1.py | 34 + src/builder/setup_generator2.py | 34 + src/generator2/generator2_full/__init__.py | 0 .../generator2_full/models/__init__.py | 0 .../pachca_generator2-1.1.0-py3-none-any.whl | Bin 0 -> 55024 bytes .../pachca_generator2-1.2.0-py3-none-any.whl | Bin 0 -> 55024 bytes 11 files changed, 1132 insertions(+), 1 deletion(-) create mode 100644 src/builder/Makefile create mode 100644 src/builder/Pipfile create mode 100644 src/builder/Pipfile.lock create mode 100644 src/builder/requirements.txt create mode 100644 src/builder/setup_generator1.py create mode 100644 src/builder/setup_generator2.py create mode 100644 src/generator2/generator2_full/__init__.py create mode 100644 src/generator2/generator2_full/models/__init__.py create mode 100644 src/repository/pachca_generator2-1.1.0-py3-none-any.whl create mode 100644 src/repository/pachca_generator2-1.2.0-py3-none-any.whl diff --git a/src/builder/Makefile b/src/builder/Makefile new file mode 100644 index 0000000..9b2f221 --- /dev/null +++ b/src/builder/Makefile @@ -0,0 +1,15 @@ +help: + @echo "Tasks in \033[1;32mdemo\033[0m:" + @cat Makefile + +test: + + +build: clean + + pip install wheel + ## python setup_generator1.py bdist_wheel --dist-dir=../repository/ + python setup_generator2.py bdist_wheel --dist-dir=../repository/ + +clean: + @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ diff --git a/src/builder/Pipfile b/src/builder/Pipfile new file mode 100644 index 0000000..e984d06 --- /dev/null +++ b/src/builder/Pipfile @@ -0,0 +1,56 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +annotated-types = "==0.7.0" +anyio = "==4.7.0" +attrs = "==24.3.0" +black = "==24.10.0" +certifi = "==2024.12.14" +cfgv = "==3.4.0" +chardet = "==5.2.0" +charset-normalizer = "==3.4.1" +click = "==8.1.8" +colorama = "==0.4.6" +distlib = "==0.3.9" +exceptiongroup = "==1.2.2" +filelock = "==3.16.1" +h11 = "==0.14.0" +httpcore = "==1.0.7" +httpx = "==0.28.1" +identify = "==2.6.4" +idna = "==3.10" +jsonschema = "==4.23.0" +jsonschema-spec = "==0.2.4" +jsonschema-specifications = "==2023.7.1" +lazy-object-proxy = "==1.10.0" +mypy-extensions = "==1.0.0" +nodeenv = "==1.9.1" +packaging = "==24.2" +pathable = "==0.4.3" +pathspec = "==0.12.1" +platformdirs = "==4.3.6" +prance = "==23.6.21.0" +pre-commit = "==3.8.0" +pydantic = "==2.10.4" +pydantic-core = "==2.27.2" +python-dotenv = "==1.0.1" +pyyaml = "==6.0.2" +referencing = "==0.30.2" +requests = "==2.32.3" +rfc3339-validator = "==0.1.4" +rpds-py = "==0.22.3" +ruff = "==0.7.1" +six = "==1.17.0" +sniffio = "==1.3.1" +tomli = "==2.2.1" +typing-extensions = "==4.12.2" +urllib3 = "==2.3.0" +virtualenv = "==20.28.1" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/src/builder/Pipfile.lock b/src/builder/Pipfile.lock new file mode 100644 index 0000000..3517501 --- /dev/null +++ b/src/builder/Pipfile.lock @@ -0,0 +1,926 @@ +{ + "_meta": { + "hash": { + "sha256": "744e7f7d38ac30aef12af9aaeb5d321d2b27751994f15b7dde921e6b6abee73f" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, + "anyio": { + "hashes": [ + "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", + "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==4.7.0" + }, + "attrs": { + "hashes": [ + "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", + "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.3.0" + }, + "black": { + "hashes": [ + "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", + "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", + "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", + "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", + "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", + "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", + "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", + "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", + "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", + "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", + "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", + "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", + "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", + "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", + "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", + "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", + "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", + "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", + "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", + "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", + "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", + "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==24.10.0" + }, + "certifi": { + "hashes": [ + "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", + "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==2024.12.14" + }, + "cfgv": { + "hashes": [ + "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", + "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==3.4.0" + }, + "chardet": { + "hashes": [ + "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", + "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==5.2.0" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==0.4.6" + }, + "distlib": { + "hashes": [ + "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", + "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403" + ], + "index": "pypi", + "version": "==0.3.9" + }, + "exceptiongroup": { + "hashes": [ + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, + "filelock": { + "hashes": [ + "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", + "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==3.16.1" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "httpcore": { + "hashes": [ + "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", + "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.0.7" + }, + "httpx": { + "hashes": [ + "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", + "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.28.1" + }, + "identify": { + "hashes": [ + "sha256:285a7d27e397652e8cafe537a6cc97dd470a970f48fb2e9d979aa38eae5513ac", + "sha256:993b0f01b97e0568c179bb9196391ff391bfb88a99099dbf5ce392b68f42d0af" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==2.6.4" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "jsonschema": { + "hashes": [ + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-spec": { + "hashes": [ + "sha256:873e396ad1ba6edf9f52d6174c110d4fafb7b5f5894744246a53fe75e5251ec2", + "sha256:e6dcf7056734ec6854f7888da6c08ce6c421f28aeeddce96bb90de0fb6d711ef" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.0' and python_full_version < '4.0.0'", + "version": "==0.2.4" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1", + "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2023.7.1" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56", + "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4", + "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8", + "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282", + "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757", + "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424", + "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b", + "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255", + "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70", + "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94", + "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074", + "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c", + "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee", + "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9", + "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9", + "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69", + "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f", + "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3", + "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9", + "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d", + "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977", + "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b", + "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43", + "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658", + "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a", + "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd", + "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83", + "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4", + "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696", + "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05", + "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3", + "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6", + "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895", + "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4", + "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba", + "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03", + "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.10.0" + }, + "mypy-extensions": { + "hashes": [ + "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", + "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" + ], + "index": "pypi", + "markers": "python_version >= '3.5'", + "version": "==1.0.0" + }, + "nodeenv": { + "hashes": [ + "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", + "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==1.9.1" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pathable": { + "hashes": [ + "sha256:5c869d315be50776cc8a993f3af43e0c60dc01506b399643f919034ebf4cdcab", + "sha256:cdd7b1f9d7d5c8b8d3315dbf5a86b2596053ae845f056f57d97c0eefff84da14" + ], + "index": "pypi", + "markers": "python_full_version >= '3.7.0' and python_full_version < '4.0.0'", + "version": "==0.4.3" + }, + "pathspec": { + "hashes": [ + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.12.1" + }, + "platformdirs": { + "hashes": [ + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.3.6" + }, + "prance": { + "hashes": [ + "sha256:6a4276fa07ed9f22feda4331097d7503c4adc3097e46ffae97425f2c1026bd9f", + "sha256:d8c15f8ac34019751cc4945f866d8d964d7888016d10de3592e339567177cabe" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==23.6.21.0" + }, + "pre-commit": { + "hashes": [ + "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", + "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.8.0" + }, + "pydantic": { + "hashes": [ + "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", + "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.10.4" + }, + "pydantic-core": { + "hashes": [ + "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", + "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", + "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", + "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", + "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", + "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", + "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", + "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", + "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", + "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", + "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", + "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", + "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", + "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", + "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", + "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", + "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", + "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", + "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", + "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", + "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", + "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", + "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", + "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", + "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", + "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", + "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", + "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", + "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", + "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", + "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", + "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", + "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", + "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", + "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", + "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", + "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", + "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", + "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", + "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", + "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", + "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", + "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", + "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", + "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", + "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", + "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", + "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", + "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", + "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", + "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", + "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", + "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", + "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", + "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", + "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", + "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", + "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", + "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", + "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", + "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", + "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", + "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", + "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", + "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", + "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", + "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", + "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", + "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", + "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", + "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", + "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", + "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", + "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", + "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", + "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", + "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", + "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", + "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", + "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", + "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", + "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", + "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", + "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", + "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", + "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", + "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", + "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", + "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", + "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", + "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", + "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", + "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", + "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", + "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", + "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", + "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", + "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", + "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", + "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.27.2" + }, + "python-dotenv": { + "hashes": [ + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.0.1" + }, + "pyyaml": { + "hashes": [ + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, + "referencing": { + "hashes": [ + "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf", + "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==0.30.2" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "rfc3339-validator": { + "hashes": [ + "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", + "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.1.4" + }, + "rpds-py": { + "hashes": [ + "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", + "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", + "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", + "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", + "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9", + "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543", + "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", + "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", + "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d", + "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", + "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", + "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", + "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", + "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", + "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99", + "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", + "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd", + "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe", + "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", + "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", + "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f", + "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3", + "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca", + "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d", + "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e", + "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", + "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea", + "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", + "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", + "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", + "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff", + "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723", + "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e", + "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493", + "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6", + "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", + "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091", + "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", + "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", + "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", + "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728", + "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", + "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c", + "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", + "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7", + "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", + "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", + "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967", + "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", + "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24", + "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055", + "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d", + "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", + "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e", + "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", + "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", + "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", + "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", + "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652", + "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8", + "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11", + "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", + "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96", + "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", + "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b", + "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e", + "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c", + "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9", + "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec", + "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", + "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37", + "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad", + "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", + "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c", + "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf", + "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", + "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", + "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d", + "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09", + "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", + "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566", + "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", + "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338", + "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", + "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c", + "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", + "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", + "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3", + "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123", + "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520", + "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831", + "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", + "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", + "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", + "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", + "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", + "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", + "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", + "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", + "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", + "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d", + "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00", + "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==0.22.3" + }, + "ruamel.yaml": { + "hashes": [ + "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58", + "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1" + ], + "markers": "python_version >= '3.7'", + "version": "==0.18.10" + }, + "ruamel.yaml.clib": { + "hashes": [ + "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b", + "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", + "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", + "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5", + "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3", + "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632", + "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6", + "sha256:2c59aa6170b990d8d2719323e628aaf36f3bfbc1c26279c0eeeb24d05d2d11c7", + "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680", + "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", + "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da", + "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6", + "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a", + "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01", + "sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519", + "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6", + "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f", + "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd", + "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2", + "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52", + "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd", + "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d", + "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c", + "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", + "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb", + "sha256:a52d48f4e7bf9005e8f0a89209bf9a73f7190ddf0489eee5eb51377385f59f2a", + "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969", + "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28", + "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d", + "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e", + "sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45", + "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4", + "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12", + "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31", + "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642", + "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e", + "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285", + "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed", + "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", + "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7", + "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", + "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", + "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5", + "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76", + "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987", + "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df" + ], + "markers": "python_version >= '3.9'", + "version": "==0.2.12" + }, + "ruff": { + "hashes": [ + "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37", + "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35", + "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c", + "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7", + "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a", + "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8", + "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99", + "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd", + "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565", + "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad", + "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378", + "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca", + "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250", + "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4", + "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9", + "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112", + "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89", + "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.7.1" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, + "sniffio": { + "hashes": [ + "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==1.3.1" + }, + "tomli": { + "hashes": [ + "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", + "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", + "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", + "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", + "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", + "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", + "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", + "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", + "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", + "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", + "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", + "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", + "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", + "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", + "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", + "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", + "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", + "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", + "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", + "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", + "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", + "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.2.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "virtualenv": { + "hashes": [ + "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb", + "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==20.28.1" + } + }, + "develop": {} +} diff --git a/src/builder/README.md b/src/builder/README.md index a0a9484..cfb1470 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -1 +1,22 @@ -Инструменты для генерации библиотеки \ No newline at end of file +# Инструменты для генерации библиотеки + +## Порядок подготоительных действий: + +1. pip install pipenv + +2. pipenv install requirements.txt + +- pipenv считал всю инфу с venv и создал файлы зависимостей Pipfile (в том числе lock) + +3. Затем Setup.py, Пока выглядит так + +## Создать версию библиотеки при помощи команды (пример): +- export PACKAGE_VERSION='1.1.0' + +## Запуск создания библиотеки при помощи команды: +- make build + +## Распаковка бибилотеки (для Windows) +- python -m venv venv +- source venv/Scripts/activate +- pip install <имя файла>.whl \ No newline at end of file diff --git a/src/builder/requirements.txt b/src/builder/requirements.txt new file mode 100644 index 0000000..276cf96 --- /dev/null +++ b/src/builder/requirements.txt @@ -0,0 +1,45 @@ +annotated-types==0.7.0 +anyio==4.7.0 +attrs==24.3.0 +black==24.10.0 +certifi==2024.12.14 +cfgv==3.4.0 +chardet==5.2.0 +charset-normalizer==3.4.1 +click==8.1.8 +colorama==0.4.6 +distlib==0.3.9 +exceptiongroup==1.2.2 +filelock==3.16.1 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +identify==2.6.4 +idna==3.10 +jsonschema==4.23.0 +jsonschema-spec==0.2.4 +jsonschema-specifications==2023.7.1 +lazy-object-proxy==1.10.0 +mypy-extensions==1.0.0 +nodeenv==1.9.1 +packaging==24.2 +pathable==0.4.3 +pathspec==0.12.1 +platformdirs==4.3.6 +prance==23.6.21.0 +pre-commit==3.8.0 +pydantic==2.10.4 +pydantic_core==2.27.2 +python-dotenv==1.0.1 +PyYAML==6.0.2 +referencing==0.30.2 +requests==2.32.3 +rfc3339-validator==0.1.4 +rpds-py==0.22.3 +ruff==0.7.1 +six==1.17.0 +sniffio==1.3.1 +tomli==2.2.1 +typing_extensions==4.12.2 +urllib3==2.3.0 +virtualenv==20.28.1 diff --git a/src/builder/setup_generator1.py b/src/builder/setup_generator1.py new file mode 100644 index 0000000..a3fba45 --- /dev/null +++ b/src/builder/setup_generator1.py @@ -0,0 +1,34 @@ +from setuptools import setup, find_packages + +import json +import os +from pathlib import Path + +this_directory = Path(__file__).parent +long_description = (this_directory / "../../README.md").read_text() + + +def read_pipenv_dependencies(fname): + """Получаем из Pipfile.lock зависимости по умолчанию.""" + filepath = os.path.join(os.path.dirname(__file__), fname) + with open(filepath) as lockfile: + lockjson = json.load(lockfile) + return [dependency for dependency in lockjson.get('default')] + + +if __name__ == '__main__': + setup( + name='pachca_generator1', + long_description=long_description, + long_description_content_type='text/markdown', + version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), + package_dir={'': '../generator1/pachca-api-open-api-3-0-client'}, + packages=find_packages( + '../generator1/pachca-api-open-api-3-0-client', include=[ + 'pachca_api_open_api_3_0_client*'] + ), + description='A pachca_api package generator1.', + install_requires=[ + *read_pipenv_dependencies('Pipfile.lock'), + ] + ) diff --git a/src/builder/setup_generator2.py b/src/builder/setup_generator2.py new file mode 100644 index 0000000..5b31ce6 --- /dev/null +++ b/src/builder/setup_generator2.py @@ -0,0 +1,34 @@ +from setuptools import setup, find_packages + +import json +import os +from pathlib import Path + +this_directory = Path(__file__).parent +long_description = (this_directory / "../../README.md").read_text() + + +def read_pipenv_dependencies(fname): + """Получаем из Pipfile.lock зависимости по умолчанию.""" + filepath = os.path.join(os.path.dirname(__file__), fname) + with open(filepath) as lockfile: + lockjson = json.load(lockfile) + return [dependency for dependency in lockjson.get('default')] + + +if __name__ == '__main__': + setup( + name='pachca_generator2', + long_description=long_description, + long_description_content_type='text/markdown', + version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), + package_dir={'': '../generator2'}, + packages=find_packages( + '../generator2', include=[ + 'generator2_full*'] + ), + description='A pachca_api package generator2.', + install_requires=[ + *read_pipenv_dependencies('Pipfile.lock'), + ] + ) diff --git a/src/generator2/generator2_full/__init__.py b/src/generator2/generator2_full/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator2/generator2_full/models/__init__.py b/src/generator2/generator2_full/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/repository/pachca_generator2-1.1.0-py3-none-any.whl b/src/repository/pachca_generator2-1.1.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..94a2e7e117dcc75f72ebba9be7bc38358639e558 GIT binary patch literal 55024 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 literal 0 HcmV?d00001 diff --git a/src/repository/pachca_generator2-1.2.0-py3-none-any.whl b/src/repository/pachca_generator2-1.2.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..534db5e446f9a6f49b1d0730ac1fff604d30e20e GIT binary patch literal 55024 zcmbrlW0a&_)-9U0ZQDkrRcYI{S!vt0ZQHhO85*P#p00002pp1n^NxCI9QK>IhB8rV90UzMc1VY9%1(Vf%ytJZy?5z5V1 zLL`xqq|iFop*4+cLV9b7rDTn+Kq<+Ef0Mv(5c>v^za@c1W?h;HUHl!t z`|CX;NPLpi;262K?-*=?GES_No}E28u`Y2;(+lsGLpU2>R4`sFTnn@7^1Ag@y=G@) z$fIk^`u*Mf3)K7F$m3)VO1;3!<^>QD=<#eW5von{hyyRYiUXq8Y7&=I(yXH32!UJZ zhaiUN1BT%Ud|(6-k^(wxXs#W`n?gkX``!aY2qxZna-G{6KHR|`ORmhqLE4#M^O=8G z;0v;Y7^98yjTL7v2s#1a@RI+znu=!7#vA6)rfUYXcA^*IfU{nVI2P0h+|c0f2`}hf zfJ;-KW>lG@L{Tv*v{rDo*Z%e_k_onb?eg}UX@d)rl3&P1KV=AX|v zalA|L7n9lrZ{C6ybrIemANbBrk{ZdFYZcNLfA7w*+!4mz549^`iaPt_?Rfd;vh6;{ISd)aqf_8St75z>psjKLu;lANV}B6lo1&%gQ=ZC!XWmzo6(1?LZ7 zK^zOk(v<-b!^P}{c~q5DEtd11?n)}POw(c{C8nUF^U2gUO8?;{?p)NurJ4-gC1%q> zpbc!;VyO%(ha_MsMzRDFf;b?GN$nx2aJ2r8J(5c$qH)|JZX3ENONusfC+vl>H^-F= zq}pQwXuJc=(qTg+?cIFiMuK5Ke2_Judyk9eslenR!sN+1b}>p>RQN2rBKwJ(cqRwy z$8tG09wQda_2PKtvJ>;|hrD9I<&0$Mkbq)|67q6nf9J8^;dJ1%2JXX8c-N#dbQFfI zNY$U(n>ar_I3-h2^C#2{!V(2A6mRC*?O?z^`(?*yatsW zbHvI_SQrw#b<6n~!XYKQ&Dc0Q=b^ZFvBz_najGE$MFQbu{bQ2-5B(nH5bPQupl8J8 zAM>`C^vyG@c+t4gta?&FP?`*@lv-lbp~H;DW3_vPw=r)$C`v}$hlytP#0;p*89r;+ z&s!fqh+m}h>96paUe4CNKcIe(7hw{z7`EY@V&S4ZW#us)I7G5z=#g?@ebGKKv5}!+ zDk-$_v#qD9A}==mE~4KLhVYZb#AL@g?MeriI#}`E=f2wG@2}ega>lKcf*=Vh@>5^RMmWtd4ZTay6@Mw zAKO?^aFk7FB27(Ay_vZ>syFao1cWbdGFO~G212xMFGE7$ad{h&UcB~S5FdHTAPY`5 zqDjS&!;b6mqh871&7`hgD=JuO1+iek4cUBZV-MUb4EwsTXLVBF)c`+E1FzM#eAf}Z z&LVl_KafhC{1oFc8lS%kHh*PiG4sB!o4Ht zT+uHOXx-WW-cuXU>^*~)IV^zhhYEl3wN>oEZtG4_9CGVRRjszd=t5qbV_0H{6qMnI z5DR6v@b|SR&$6nOHq`qy<7Dm0)|%NNNHfv!XR%(aLE z`bLzASYzD5` zu!mCCT)I?bC#zP5=;^@+^QcKM+>;>!)pez$-I7Bo*m2vrwOCbQApAxC1Z4X}D-;M^ z%385Y5UnP`DF&a)zwm@w58g}jb>aT_7xd9O0 zMk+@2V;=j0Wvz|ik_q4tFcv5;;#x*ZjznKZM{0GICEPu!nbbLwBW?huI(>NW zJoomVMqUS&)s8c2ElLQZkG%Z{1!G-n#jss+edT!!cn@i{0d`5o2nFsgxNeVqBFqLoUWKn%#OSHzFa~jccBpr2x3f7WK$I zKqY4*C2`A8dw)ek9pVtycDn^9( z0z3kz##F)kL_>;q0M6d8M100{rNJHl{U|(rXqZZt;4O%ZIk=`KU(|L9WS+R#9?Vf4#I-d>n`I4u1AV1Ocfa0NN(Wl)4^yCIV*6#N&rf2xoNgxb;2G5p|9%6%da z<+fAetxDMt{27$Ga06-TLFl0k&94c)?pOflLtWR}K+g78Y5Q*~6NpKv=L zChLr&wzEFy!oTd!B6|h})__5?J?L~-UQrUEOK4(&v677><6a!3kkY{Vcqr#c3p5m3jgu|_q-+|oueMxrt!8ZpmvCMF;P!%l zX1C{Q1NK>2wIv8F+z}V|8kCeLZc1{RJr3GTMuHWd-zsP)}ZaIU~=L5D! z#`7K$CDyfCDOdi%NyC(BX_2K;41%$ejcYab^anhsgVjjg@JLzu zNAk__;baqtQ2o`yFTJ$_t%eJ(M#J|ew<~O+gTAl2xt8m*NEO=`hvPATSn_8O$#fW~ z4+oV}*7D;So)Kn4p&q-*9Gek+c0=tVpB%h9EF+Y_eRs+3yQ2xoVoDz&bQn{(dmdSv)!3$!*gj8=X$jk_LaR`li@b+3+y8I4$x`b{JO<5m7)2td=JD5_b zc+8ggKyF$+#aj9aKibx6@*_*Xlp}S*t7R6>YrFsi72$IUPIJtYcxcH{ILF4T_ZP<- zP%H4%%TfL0pb73%nkG)j=-4$zg{sz)8ekpd>8o|gL&hkSi30ePn5J6!_1wtu%5)!)8#+rv`-3IPD% z$_@a4=-=222V;9@V@D@lYhx!fTcf|+>lUuIE%wMQ5C7+Y0DQ2K9KK2>8DlS)8PXxC zdDNgc6_h`s>@;g(=}okFB!Mq2t2k^28c-wuTrtEv_d}A3a6~fc8$HgK{E6W&+h4ZV z5k!=vGBgUmI+zPtw`U8g&L>BbM9;_6;&8Gx5`>RE!}WBl{;hNPun2Z{*#g6pOfW}3_U!DaTo zC4Zx<`SMRSe$%OX&&u>w=LRgG?Fn%Y`u6$0XAsh$wClniyFB^{Ee&93=|``vjflXn z5g?Ik_d9LETFoggx_Ba2t?+E`2mQs!H}Mm1l=*;4n?1VNBg@JFB`X`P1OQ$HS|pkF zF<2_V&hEA}cm%9OAPTY#B8S(b6z&&8e>6w>(W5Zf9nYp<36fWHw(6F%F4{`l z2_4cKi*y(xJLWEgbe#_I@2_>Ltc0v}H5Sm%XXy_K_%WMF5qAAXN+AirSt&!N@R&7i z)8Vo5%uK$94m&>G05;q8iPfvXO#p~C-3X#(p1cE{7)0m41DDvBjVJV*Djh?jCa-Eb z9L#{ao~popcN{k!Sar$XxW2d!L%FvNb0PKB!0uAa7-_^tS$(~?W+D(|TAP*O_a0-a zf{+k>L*r`RHD}W4nwrDw=&(Y17=q;XqKbMxgRR3reS-(~&pE50pg+xIi?sDvtr z*QC4qqkz}7?i;tFdN^~@ixXK2Osq2amA(T20>w<#SuZR!;^YP>|b^j}$ zpnW6s_wP6MPKI+g=j-P!T>O#Ks?X-$lD59s_8SQF|LY-2I3IyDxuSA$npCi0OI# ztHHCQ!12Xrfx+Nly`x9a-iTetUuqZdoLrFoeZhr6;PyduaNNb<$6I z(?V$B@)mRP`t-0lpqQtWUcWhr1FR zUmLHVf3vw{beWI`4hI@@nTdMW=5}!Z2KppyuG~cQ>;5O>{tiL#}ZmF~Fojz2He4@)wdFDu?!0mBv+3-VJO$@1H8N}5A1D+MtF zpPzzjc0uHaHzHGIH?^6=^x;Sj%}0@85B+(Mw_++(lz}Oupa;XTw*g3+urdKOxDQ5* z&=CjGTZ;#%TMcQ1=p`HF7SixEOycG=r+x~DryBPc#bE*QTQ#-8>Gi)R%mIW3Ivr!T z8jp2D$%x+q*1`NiqY@=$;CY_NQVi~n7pHGT*zphf zKEi6Gq(H&RV8;1+pO7553k9TjA6s<6VeP-7`7!gySKlmA9`6C#8Hg(hz zB*J5aJty{-){eF+%cxpYeSC|!8)OBJces)JPp?(Fs41s8^D}$Hjm#c7)cEujjmb+G zjCU9OZ@m{X8q<%ZDC*YG$0_PY2j{N{vdZWluwKkC0Va0igKGk zD%Ri1xeI2ZOB~gHOl19-Ngk1+ot%$2s10|dF93HhNrHX&3OS|A{VA%mE?U7#4QMa) z>-7u$>h1ceJ$K{7IeP&KZfcT4MR!P@aoT1_59jQyf+DL=T!ldHfW(O!ZY*F4ogsts zhPL@2y7QtVhK}bNXLu0)vc&A2fgO}}sJwqL=|Q1H-P*Dky&$V{_Oen9#_zP9QXiYi z4j9U$oPdVf|6%^*HXbhM$`mb8H%M@gCcH?o{#j7|UZ(rHF#gvqodJ*{r)G8U(!+ZzgX)z` z&Bl%hS-YN(wEbDX7Hd*ec2P<&vN|J0Tr@uk=bj@tzEhn;FrW#(HAR2uej4ou5uU0B zC=K065s|YxXSHx5g^RuPFx@eFnHYl%Vzn4J1syj+9K$D36TgndIgSMZu>@u1!$Z3M z^6gmUO)g7f1eBr8rnSF*Q^@(x; z_YR`KpR^N)V+(_i#}%DFQx(`6o%czc6_J8}=>2mrb$aQwnkHGN-E>Hel9FjzAS6LW z+LMuVJGx5ia9^&HrP2r#&FGg7lJRZE(3^FTWf#Vy)SenlW^KGt8UseBCw4Dfm?N?B zyUPK&H#VaY-1R$RJoWDSvGNODI|Q$0ktZ+nMm?A=ynk*ily@tcmoBDxr4c8w@<^X- z?qQ$H?7g=(6FbUo&PK))ZFKs--;U%ymi)LI#)%-XwnqgUY~KUv9=g?6u}DQv$xm`DtsKeX5Xo#S$Dpz?{2Pe7Dq0ivC7U=&Ow zfvdRyWcFOfaw2AB-MD(jENv*)j4!-Bi|q!;3QQ&845-ATS5eS=3U&?vP2?gTAfJb| zgo}Ituk0LBT7i)lOj5*g7m2~NB;KDOT3tW7@EUY&^}!U-9&A2HJVY817rTf!s%{g{ z0yzeuO-9~b9Ij1fH5x^ODQ=L?SIEw!=szj>juvJ$L~?W3F_8&G*4DNfYtYXF%}U-7 zMV6~$9(oTGRZ6YpOq`bT<0f`Afs9QJ^DXdvG(J$Oy+1K?gb@9G&O6=tCa(d5XJkiO zUsBjW!z$>`5plAM&ZL_vLDrUzisZdsrk}>jR(w*ju2yP#Nv1K;M3Z)q8+o{Fbfn>@ z520s8P&7T|Me)oJ+DO|o;fx8sIgERRmgyyQ77AKCS;vT-!>U^Rrud!Bx|!9QFwd7bRU7|R;Qelg)C z-Ob+;?k1*2-tNlD@WewoRfmkZ21h9N5djgWW}`c3z;Y+>6!l4_kdXXtRX5JNwd({G z7#@#2#H9)ej-4Q}Wfvi$cTNy`g=nNzRZDuNbz4|+a2DZ5CRS`9nr{+zco8cPVS>+n zg|Ng*MyPpDH^cU7d&8+C8qOoMG6ZdiBrLtmE1n5N6oKKEkYZBV()PHGq0AB`!OaVM z6pODdb`cWSq*(6!4(ZR6>Dy4b#!RK<uE=!d2%?IvsZk8(BTA8rHSU5iE1lzh)G-{Ucu6EO;>`$D#65Ge zUgI5xiPc0BgU0$z*r*X8HUkh|>CwJ^fDOdJeR=s8^W6`C>|ZNw=7%K3#xxO!d)S0% z!COvNQe-1cxukcO^()-AV4ovKaTfw5tqU1lmy^0tYAGv_n8%bAkPZ;HYj$^fcepWW zE%91CLqE0O8r2})yyjm+wfq&EXfPX@flS5;V|EE;8wnvU!?Vr3YwoO$Q^K8Efzi{W zSgOWI>*lIGWYODyC4&86uT%HFNcnZXIIE626O{s%;gjBPyyYWJt{!DK6=cj5k+tVW z!W{9jNqLv%YH1aXT(O0jktm_rZFQcnF%^fp@uN}@%%-!X&Au9!F2ij=w19x{4`f<1 zAGvpW7@v^Z-TR_0M9R!_sgXq;`oL#dM}(>R3sJ?*Vw7J47r}0~+T*(^NNi0VE>^f{ z10Rx}?}??;yo}rLF@U{=V&O`YEJQm!CO8NfNqqR(e6g`%4^1E!(iY@n{bK>duc*t`N%_>P=CElKU?7p-90yumRubq@^$GQA|7-3C!>oor>z8W<5wgkZTQ2s>1iN@0>|d| zc6ZiKcF3<#py%S>ZT64lE#XYED^Gi1OutOu#CDQ2o~c7qVXs4!3A`N#>@AQ`Ma7Lf zs7_z!yp1noM2Tv%hrc8!-z_;HN##j0pm1lJqM~52PmPt;(6tp4?3Hi(2h%TDnLst$ zcs2QByxqy4Rl?%)GrPs|3o$%yW%ElA8cCcigo7w5&4Ex8jI@AD{Z*J?N16m8<+cmV8S(p2=;Bjj`~du)hs(6kBpf z-|E<#X$RJio!ttJ4(=%E2JKQDg0WSF$%&Wt%U&Qngy=%>)(~?HnTfC8k)~8+Ss^XH zQq23fXs^>4GlDj{cgm?MyfPv?dH(n#w9hCOo;HXn5mZehXcxF~tW%u>(b2vf)dx|7 z@m>})LMk}b$)xJ7y!30|b1rRE;WosDE>w#!AXKV5!e?BEnzLg@zU&}yEVYN{Nlm-0 z+?1kr+D~On zl7DT&|GQ#|wXKn{mE-?cFaED`%f?=M|NM93OacS|fa%|qTmJS5|NBMvyZ9n#You%F zV65+CEM%ttSD!vBVM^wJ0b%4i=?$(RTZ8f(SZTjs!ec!MoFAesOq1qFGR$N5ComF{ zNG1mz_!A^hhkVZjb>vPcCb$Fz0V>U!47cITHJ{;gJOzLkQbjF1RcL|m0DY1L_>*B( zzTC^BM%S`o$;%*ep33itjcT!@>(PX6V7{aW9+%1$E!{%OcMi1nHWxGJbJkq6aDEqp zCCJM}&Gajm4M5pqn|!O*EU;~ZXhY9j`!Hl0tSSdvf`DqN=)@G4WixOo_gq0Q*H+%T zhvR1Spn10sFYF`uV-vGrls!PRml#kw>0o3>86RdQlUAmZR)c$DX-7v9CF)}$ML)-L zMetE)<@R($G=5PN7@KJ+Fcz&snm1$lg?%G6CR#EYn0rnhD&63=Y&J-$I-*2D z$-hHv168TRUkJU_=Wz4373(ma&Gj$)NsD}bq9>pnEw|^U8_}m2h%KZ}81CrkKgv)$ zGZ#D?_jTr9L;f9Oe<6f?hCN93ds>4F3IKrhze9+$v7@8Dsqr^Rnw0x&*7*^-h;QMk zWrPJi0Tk%U(iIc%+$#|rZpgItttL7Oi^w4atP@M)+|P?Fmgw!o%pd?y&|SVtnLC;p z^$Lsg#q_SHFDEzHnPU!mEs@V%)&rZo=n)R1Aawfc)i{1eoW4!+h+EZQprhWcqfa{0 zmZ*hhy;obe`LiOo@I)*C&lJl9T{54qo~qHX;6^ysuORk2x^X_Pm7zj|@cMfrG_gEs z()s^bV?CJ&$(E!ZEbhc)xT@9s@eq2&+6TS&>i28h$|A)@s#0dxiaOC6(h|E44TfMX z%J6s=ELL)YaR(CC%ol{zGkFrtQj^?WwkNT^?x~MDWCHDK8NydAF5UWFsbXo|pea!M zQx4dcw$(c^*l>mP!SMV?)@b&o%D|1{NOFXy`20QPa_Sz|M&^HeWm?Rx>DMXaSb}?w0-H%}X4g#-MK+lwH1dFmY zx)-PqY#n(3ARU8v7U1+G6l#XA5A|&w6#jXMRoEZav4h$dTcB2M#19!UGi~6yDiT8H zfW{3R0fW!_8>rlh`jXvqM`krQ%R;-HP7h*mz10oQ9nPh&j zyRCsl{uDrEi8!2elxlTUcI~I&czdN{WnlLRu3X05VaEd%aV&FJ^o1Af z(1}e)<7G;-g41J}jw#oM0Z#sbSDniJv1_~VEQNm4PSS1A#d`aNPTH|Pz#|+I18s!# zY-)gEhl``yduYiR(y6oKz#HO%T}=7G9?*N_3Xd+GnX+Nsi6e&*qtl5)En}B&7tpn- zGIJ@p14STLU@ehfP_#>U`Li>FWEcAsQAtqtu`TWg^CM@GpuF00P#RV)Qt%i^L1eyj zV1qX49rcTE?YC>6>0QDQ4D_~)eky1oY41r!e(Q$;o5F7bQu$O2AiUU~tjrB~tC zeDfM#=g>QtqikBP94tD#Ndlf*cEgYroTDZzUv5cc_ZOc!+QBCf2>p&4d?Tu z*QDGSfGYvb=4pVv>nso;|idl=cDb;*4M3QYSF(0CgYrz$;b0Pi3d^p2fKdAtDw zI3v8tgui@mR~3n%IT|O)?*~YZ>9W$@-j*k)s$Qe-h`InAZPAWp-})?$S`An5Z=swj zm%LA7j^X;MA@KYXSbLYEO2Y#j5t%wDwB6um9=!%zPItzo0Z-D;!mkko2=@<6d@{J}5#v8S zcbEAc;k`6>dy3IRouN&VyC*VYe8u6~iP2X@OUS`v@OV!fX~@BCt5O=7{4A?}Z1huR zj3>2E|Awy5SSU2yE)$=pT*c)WEk>DV7mEmfEGKx{_M_u8E&URn==Z}ri}37TxCpll z;8YbV1F8n|A3}Y5z%hbuPjHXAHPtGSv|8Dm1n_a8p}WgY>Tt34j!SPtqVX~CUKw?J z1TT`YI~aP^Z685OeXvtAGrWCKW0*1Fi;^iIl{* z>IstJWMevxQbkZ*< zIrr@){3z?K_+koC*dv<}2-Y{bDAS@CR|ZYN^4LzT;5@K zy9fyjNe4FZ7DgXYQ~)O9apldI&M^N5hS83gf2<-X(d2-IMWc}BR=NC=*pN)gScBFR zU)F2h1x}utlNueIe<3)S$b@A;sD4ax*2;%1&PXMtiQzsTX%{ zW1Eg;m0CE%ob~AiR(Z`(?~*FaSy5ER_)#;^>+VVmoM1J?*$q56%V7>egvY*bp{B&= zyadwi_OaPK%=VlF{N3m#V$@SS%qQR;+mm|c3^ZD>tI01}vxR4n`@sqIRiS70M}L-W zW}P&k>v(GCgXDaVAFq-%8$S!`M6-Lkzo+$D6{UBCN6Hl-TumJJ@Q@gtt>nZXd6A;{ z{@ESbyNJRze*5S8Z|-IJPtk2^>?CaNU~K55>|piHzEz4_GW`rF-Q;_?>Du~0^!)u% zSX~PEy%_UWpx7PGYZgE{e(A1+^7LKLpmKzfU#c8l#Il$^>OX<{<83TG-n@2Rr_D)Y z>ExYrJe2#jb-}{5Uc)70!mY?M%2KU+e#^<)dm!3L3AqsBlHDCfGVi7KS`DMIz>IM! z!ojCj{RWQH1j9pZ!1SL9dqBBYdQA-JhH2ZQqiM6H#06B4k}B zz9*$BIGtiM`O?m?ObfL0vM>-t*(iU4LDpV|PgsAv+l{hWZF|Na54lH#p_fedcuRAJ z5yKC@vVDSf3f4Y9&>MPcs&!gGd?g&;#N>=W?$V3H60i`3X{(x`0XPRm-H7{8xk3h+ zP@WcE4%6E1{AId7{98a(`dN>am}Yf!oZN`kO;MRssgCE*kE%|_CcvEu1>jgJu0!RR z{UM%OmrE}t3#;F|T>aFu>ylpzCPZOeF1;0j3whoP^c}jzQ0UmOQifl?aLwwf>@9hM z(f@*icnvsh_HPtGee>Lp{}cswwvOK%XKi5Y;HYH#*J0|fX124Oq|5*V!j|Yb?oaI| zg+yTC^I%YF?>|s^EcSg0NTPM@TXVjF2s}WWgar9uf&-|-?B|1UK_YcVF~irdQyw}f zM4(NRZZ5FgQzCi0fs#jkZq==${e#Y0rgI5*#yBS7qI``7a`lRc4TAxO)A6n3?J|jh z3jIN`RK{nSs0v}HWJ(U5C9*&(fEs8$`*kprqnI;`q*7I@s}65Rf4ZMHhNOOivTqj? zdk#y~JV0T40{_^q8?K_On|ogLLQ*p*v8}tjP zM^wb64TKACA`zxZ9j?0?2_}iGNg}IO?Eg_Rbu35{(w`X?`H^uvG)d-xEuo;E;0|lF ztwuq+i9yfWwuIJK=yk>c%lTL`uSl*o`bdtor>h#eFfS5e}mL8NQq*aXECKk zanbHCS1cOjDP3VQu`?Cz!V@0e`qZ}+2cBm}BrG5~sbgN~k;++1SBGP;X`s4cNRdMO zL2w0BD~0aoRwB)tJN6Ip)k+NjsKuwC%&LzbBS)mkO2m@{Yvnbzr|+vb(oM+&H|^GR zKcQop@7lES?b@<1y~!O|p8M)NJjIwtJ`@H^+n%3F@(49MM}qm3WWSMwpX5w1ya4_) zQJG4TLhgRYg5n#d?Eg(nl=Myi0iPn#eG&uw2*KCTf8c~^h?yP&0% z2(?t_aj8k`-;c4WWS^|5uOUS&gF1ApPrXFJo98@j-gAllIgE~>bjZmT@q&!xE)>NB znOMCY;V>aEOOc4=5u$=>@{~fUV z@4ROGkAvpyr0AsYklkhn{LZo0x*)v=|Z&FlxzqI2x~r8J!*BbNzok$Y;5h-BB z`Bd;>eZ+j-gLNjeb_`^UCXr@zhcbR$D#~bd>9j!+X$I+ zk@B1IQ!G^TgtQ6vVcd`vGHgOvymSzO8yt$wH{?dPcK+L;19gg;Ze{UAXeW$;{HAqjvFP z6CW&Tctnqv!kd*f(5;jyJ^g!qy?X_w=~^!gf9MyNRWF+k{b;@2V=|bCoHKA=iQGR? zhKvGLVMjkGUUvj|kHU7DOUI}%c*4#u+RE3Ivv5v5GXN}&=8chHi1w)u<%lb{&yAteS6aXaTc&JFnni0Q{t4&#$WsucLzr-6Ltt3k{!$O5Rk1A?k<9(@+4UG zLuaBx~|Lf z17CncOvz%`Jk#xl=phQcMo{|8774jrO?XSD#c}jj94&M;@Y8dIIq%34b#yc!B`*>P z?$YI5%nX*xyj)>RGw`9M9XI!)YqA+F?YT)DUawKvx|gf+D%P7^?I1CKGq)c*{VfuCvJaN3vvAaNz*1+~)@Fq0 zjX+b4WT;(j=Qi7Qy0*|Gh}4loCS=JZzo_4vG~0ibT&>0R(k#f7pb1UXK{_uv#;4#z zYZ*FFem+756THNl#h~5Uj6ZzYb*g+?AKHDF7PUf0QU9cpTy^(OK972rSN$Vqapz_` zII`oC=N-Wg5y&O?;28PoqjrePYBuMl%>wM1w9gkhV=?(jgdp+1Pq<= zes44EX9OxNZ#yzOX#%f&Z)zeH#k+|Ky?NhLb3=+~5d#B+i@>sn)4=HkcU*6%79YOI81uqK7O$MR zLU3}7{6eKqXMS-bYjmslMRL1hj#KRR+Kj{mF4ra$Q!RCgi1}1(0Jd*WSXsuo>1I3t zG-qsek@?nWqe{X9m3^={eiq+Q>4DP$s*K62sR5bPlY;o&EA>m7yH} zMq6Il3`ZZ%HvlEWC)qoXjX#cEX!7CfgG3Z6BOY-s_ zL%sZ+BSxZCT)`A9?MYTpEM8yO*Jq5o_%TSkP803z)_)QgYleUonnkTtp5rvOnp|Rk`zXxL~IN{kUhH1-Yxpruf*VG z(GQkEhIaMn6YEu2n2y5@C~&s1LuAIE&N6FMo7*kmvR7m}Lk5i$FZ1uWHF=6hv$Exi z;OcnV?=fq+gs?4=QK~$;SArt`_|<<&X`O9l!)t{!&l;1wyczqHk?c@=oYGc7Ajg}< zZ(}cB9zDPhMqB$Yhp$6b@k(C zR$7-&djhg#k|YJA=Ly=i781iJz$4MY*df$`*h*cB|dhXh@8VlnyrF4&tC^km-m`y7z%ft*A!Nh;%r@$)B<7 zEFCI>B?u*y^EB%P1ibAH7N>*Knum3QD2CLNOf2XRv0n=yfXgK$JCgKEfpxxhQXZ=F z?2H+Jm_JnTZd;E%j}V{;{?#?8EaVJ>AtAW8WNtIngg~;ad*h+a7`?6g#}~G=&Y_OAF=P2HY zE1ND;%Z7gjF&?cPjA+CuTL{nMKEmL1z56W-w&*rkp>1e(U|Ge$IoFL&s~D}H2ch4M z>&#vaI1I@yciPz0U>rQ6B++u6=kM{aN>3k%ox8n>CQ$@7QM_sESSwMMc0qo*T2hIf ze3LS24xMVr7hKpht6qV7mIVQ8As^MwG!|}Ef7k}q$NeFtk1$o^PN10%X<_x(sxw#S zvk>dXS9IqA50944v&kO2sd|C{ZIc=9%8DHXOt3+XCp`SPN3Zhw)DQWQ0BiE;;M4xZhF=`fcI< zZ#eD$&&Ay@DlAg(*VdyOE!}G9ppUVO$(3oK6zWht&YCiSp$qx{foiZ_OmpUK-a}H- zr@VFlEG`HYpALWlVBPKn5NIvU#Y;9Qr zzpTsu&BbB=<>KrOhL2%x;L(mTpfe4OgTGyzWG|Q1WUTkd>TY8GW$y5|i}OdO>4mfS zc5wy+mb%NfwxUFDB)By32HKVQuCm;wYI9w~;hZ!jLk?+XWh^_PB_vOfY;ZA{RW~q& z%lmTGl#6$_x{bOM?tTnZ?sJd_yNe>&o$6E)&f!Z>V{m=vhwZze9iX8He^IQGApxHLvJjf?+n;=+GMu)@k% zk4TRd&Y&=m6-hw#q^(J6)OOjRZFC&(i#KX!L*N(wC8iTf;ZoBYo~mb;Yu_HuQE>f! zATDF3uo>#YgZ#DCVOj@z zgT4)`1!l5B5jNtn{@$nbC@00nlXX8MndYlF+SB{lqHK|Drt`Mex-~m)O^B?9>-G8H zz$~l_R#iF;0=r1@hV9A*B-F%^1JUe>h8*fe`o4J>gC1CSYPA7`o!CR2mcWEUJ@~f_ z`C3d=lav!QoQ@s~4P6F)p0NDsJ#C0!i$rv&aHj49<$1gn(5wpVw|Q72*NbY}<&J8y z`(F7rOTyYiB|oYAwwk&CY551{(1d&x*a2K3ZveQ<0l=Dl=sRo9wLVmYUb14?lL`QS zR47L0c>1k$O7Q`FxrED33X4#q&Pt#J@Tgi;7Fl4b0Iin08ijz`tl>ppxs}pwEB1Lw z7+a({rFHKvf(H(=uKn;5`DISPSdFee+mZ&h0$tEgzE5)~^*hbH#3-}gwFemgmqZ=i zV0+Oj)SycEO-$anGW-6khZ|)v5DhKuk`k^|0ksco413sW+pr9V7>5vrC@kIvjoK+A2QAjgsI)iFk>t=jjwcjXP3N+?x&FY=Y zO|J(u9oM}!kvuSN@JkfDBqkw^O*!J8AdR!jBb0UUXlMJ9mle7QX=+BGIppFe!{kA# zsK<%6A)6(gGg|VwF~BM@*&S?~=ol#A1S@K=bu|`0k#6uzwB3LT^!z7p0_8sA-V}*W z5=D*E^o*0YlYajc+nf~-;r8sF&^k}9UyOw-gYmpn5?|QOpU!MvQCin40r!lZ5HKK|(D}mM| zj6c?-XUFO$IWiV#<14%No~2}oX7tQQiONSE_LU7YkjK?odOHH7@5}z$&IylE{+;bS z^B=Zzs(;wdEB?iH{vIvhVLQLi{HNRbRkBKI2ljcZ290V{ZaagTTxsj)EWwwpZXa*> z3tHBih&c6MDPn(}9$U9tXoGhidTKM0XVPdA%4nQcXCs(uNgS5RqNs!y%bVjgtYNjB zLereC>}OebTTx|E`nMPdm6EdH!=bCJhPlG>vn|NShh|SNz_^3<1Z)vbEb)0dk@>=( zhAKU_HFs-J*Ho|CLIA*HE~Bj-=7?mDX@T}xAKpT}97Q@n(rnjrMpz=HzISI#8x6IL z&L!WBU6etppDRn!Tu}9@{2<&#W_d2=$npBVCZz1w%7UtU_!b2GK>}0b|KJnD zuo-Qo_^c;8p42y|b8l(x#G=`PHz4s)VOcI~GcZ%Durh_1!Yw>aSm1E%tatVPO_CVb z$%cK=5?9Ps70HbRF;oaqxNDZywtN>cZ-_FXq)r1?XY;f3=L5EeTmun@vJE1imJ7cR zGoLm0RYJ^{I5_M+s=Khw~rvd`csZ)PlqjdjK z3r4Au`?U{?$Q87H7RoSL1uOn8w#(>h6fmq7sVv-NRpmNmTb?b;OT8Gf6Kr9! zL79Ma2%fLhN2b6*hSg7XK>dZ>g4zi|+11aFWF4q2QL!P1>Te2G!mCNxf}`a=AMvh9 z-S)kD_Q|51kO)J{(dDuDQ$_u)(XiezF81ueI+QKh=X7znjSiIN(9wLPI*>Wtuq|l| z2=txHhS(1F2VEXx=2K`|w9&hr`8|oJHnA;j^sYHF-*sGW-IL`@-JVaz#Z_su$NC_( z4DrfjAX`G`^yMV-g$ZJ@jk^D~uMlsJ4Lk;39xCwiB>w&40;rSU*uMFR!Tia({`l*k zuMh-4KfJ;}0qCksUa(jIfTnX1DB{vGnfV=n26h)G0D#srOyxKKlr5+x*_f6}bpPdc z+9iAH(Kub?$+KR8Ok4P}jX@tGylmoqNum3rXywA$@cLBqt-!Nry7LWX=rb$}SF#Ib zswXJR5@>!Yvj>oo7Kn{g>c$fq*+1~-tlk>zSQP0(6y1hbOD5=7^DiroNiiu#$8*dr zRvA-fD|lgCTNl&x!j$L^BE*Pwz#IdriN=pGO;Qx&2$UU#GRl77fVBO8;DGC5>B0yh z*=jg@l*Ky4#Ei-Y1w7;YVb$et)B~RSv~_92KlmR#1U39nEd|HGd52*t6K3;wwsHEtwIW zRDb3&mwKZ)x0*m19P=fQ<^v9B^<@~&uHB9!oU9)z*p3}}%2E$_(tv2Tq z&6m5_VRZhG7?PSK00+G1ZKJ&%diBipT{~hbIDiB8fpEb7pEw`}3kgHY+vl&wRx1}k zI3NN!2nQVhi32tSFEm`7iae|?z7oo&one8(G=>_Q2>d$6(im>lb=T*;sE1U>)FV9; z0yeFLrPry4w6H2KZX;0|g^Muog3JA`VSlZFp)lu!AS^HnzykjU_3;mKGfO*w00gzT z-+{ozA3z`^2nf8)pa%hgCI$Zh1QvjRz{da(SoaqYIJb10#m!lvT<44KRno9DHx37BE4yl2Zcj)cJNmr0r|9=)hXa;t~9sOJho}>E!ebtSjW*t4Z{w6)Uv;NEbu5 z>x!c>cq?iPNNI#cTHcGGJ@yyyLwk_l!v}NBjXSn?p-WT>tcli&1z!d~@_xNyM6V8G zX*{=1)ZvLyE&$geWf)kU3c;I8BKhid_=|VQar~nl_+Vt{QbSDcg;Vdy-I6O_H!DNf zWy=ONKHXLGKYib*=mQ@)V;wBFi^Ca%!KpCvncxXort`6T1~ijHVVD7|htLy7oi(6& ztRXm2iv>~OMKL4#o?1ASvUXzR)1-O6?-u^LW8&zY|dJm22rets>ca1h|T;MF-yn+Tz|gqfE`{v@Vp9 zj#qjS^ji^oJv}kueDXAq6d3_ErVh`US#D8cN_>M^jQTh?Z}?Ft>f_+5OX!9mVsQDJ zi13#Q&Iw_UpBclt;t#zyhW;3{+c4zGWgfX#bk;IvE9}O)%Z$~J;%*I&0~wrq3&yQe zF4rW(88ChkH?%_R$?sLSPJ`x;EF>fC|D8 zH)%Z?Ev5}{X=Ir&x;TaGZ`Tu)$?0zOU#uJXxmanPsDFM+;Oam(XSi)pO3?ISMFPd8l91!)YE_BTpt7PvaAX;x0w~94|}ms zSA-*1S@D%^^2UE#BBq|JxEbQeFJuz^6An6T_$A@@cQ0Om4@W01N)ukARy@@sqWq9{ zHPU|>a7<6qtmy)&tG{k(?z73fylssv&=yDKRym{?uhgg+f4qSF8xrU$=lK%}{O*Io4}4<*3>a~V+V)+P8X8?uiMJVud%M=|zXO3~ujnWV z|30VoYeD;0t&}E3UES)BRytr3;p&r3qY~mhDV0NfgV^1rBW|e;Xn43Phttjefy=#o ze@UeR(R(V~-9ri!B+254w?*6-C-9|>pkU|zb(93wtwQa@0il&^RDgR*pHA~eY+08E zR&cM+YwFAhh=x?s(`x_Je?$QVHUSh6hD!?Qr9V(WB~UNr63;XlZP_b6cxK~@N#LtC>j4e^Y zFzw*_G!3D6TT8!-Fm6JxPP$4tsjO28{T7lSpeGdI)C5iL)rvtVphZ>sPZW^z2MXx& zfCAQnIJInmQ>)xX!m{rJI5jp9r$!v{z^Rc8_2Pp#waYkc3r!f4?ds@3-gNWh4A$mM zr!Ne!cI{3a!Oqzk%BpOzCLWtVZiECzFsd z(Fwk+`3${$vdYGwTgSMBK(li&K#CThe){>~|uUn!8T22zYe%fQ;tf(Te?)(Ezemkc<)d=SK%^ifsdJ5dNSIq9_G@&9@co zu~gFwNWmv1ke?r^V41C(z3aPBUq;GjPf~rSfEtMkgKX(ZDK1o!E3@9*en{|4KfcpW z9TuxSYNpS*@ob2nr9lJCA!zZ$tW3sqX3OiToEe~@`689S=j?Qoh0(_|B7J`&Mpuq45iCG5a&m^+)cja{6fKhAe?4X1h*< z5^b!U4soAvkc-lig^3DKw*?;&L_Cp%FBL#hz98+Z{;m^2zYD9{{;2z%u-;IvWw?X_ zG?8k5#C2+}er+67Ln$Vo7ZWP~D(M#7C+-g0c4@g(hLK=9%bkv*Kr>pAke%0xT_ZE( z&&i7q>34IX@g9Be4rzER5xV#M7HK4QDf3qTT?3PiH`E9J8z$}<0 zE9V~Ta@Ps;N1D7CokOjEqKvU52cZ{y>oFOJna-n4yVCNqNk0N-55+<7QzH50jQgN{{w2zw`71OC2$u)k& z)D^VEwA8wG5Cgl`g4y;)nhkt-NtDtuE`}82ntl5-v1O|6xe_6tmT7=OrcIv0 z5diQ1J1|N9NALg7g8N@LXt2(71k9lSc7?9WFpo|GR19RzueQP^7zJQ|su)~XoRL|U zvKrGx`_M$1l#MufWp9Xi-+M1+#YeW??>!H^jibX!FzbUIVJA!)41-97 zrKR;Fo@z1|(QhFLF6~ewj(RZ6r-4144w`dd?v$D*hzjQNr%1VcCou@tK2eNluS}i3 z4%B}=mpUrflz zSoGG8n{)QKXmJ8__fekQyhhT_29>fd#4h`oyj&LS{=xASBY}1@R4*;@K|q zmFO@L7N|Cl)Fz|t&*EnxXl7|@6Z9j**lg%9>9CWKvAm1rB?fG~B%9PoEuALc*gY|L z5f`o9KlN^k6dPlxHEfDLe)8qiOCeTIt3pv4I+ZAo*I(GwbmrsoN59+e zgz?K*51(zUpM8vDEG%>Q%J3E!6<1a{KexU})S0BYyL?t9(!J=3W?Gwm<_d(0uVy)B zA>3jfG}ssw+7vGq`s~M$RcAQ|I7FC=ICE1t)577&eA_Tvb5+_^qLrAcuQPE=iyvkI z$>KXY!FE&Vin-jho)k8HZUrRmxp8zZW>*YUwd!IUn%9d8P4+>y_~18YFXh ztBiUE;YZFIDSe{Mrt?8AGU)v#+fkA1)K)6xC%1}QPGT8h1H0ReE1R%WF!8N80VdwP zF?hB{u?lxNMeCdE>laF4fTF0Sz#ZDNu%lY_QysRZ&v|($Vi9I-F9s+ZmhmZOp*bHt-`ug!n zBax_8-d?VCa{pCP2A``?6}a2lK7k z>=~`dImWNg|Na&d1~lW|1LgKVd;b4dZ~q^yw{>lIV;2`4$QhbjZ(-?|-nJZ4!VtK} zxg-e^tzJoZNU^vP`q7xm-$DQS;y#3$(t;ZN|KP>_lqrq?zF7dBgl_4Gh(_Y_O9SVu zIv>fA$(V`oiC`xwkx)$^%D zcVBK*Z4!2fKi@r<45Ql3;TqVn8o%5&#@r-s3Pt>`o#&K|!EatWUm_GFcbk#EsZc(9 z(#gIXi>$Igb|&7H0a>FVuumW~@=@9-w-RyZuu8*sFLn2bj^!wshx@~lvqK(ogozww zf0leAX^7_bA-2a>0nr@Gy0+#l27_Za26sfH7!O7BMnCc~_gb(~Akfz>n7#((X+{vl zxCZs=4HRilmss?;f740=Gr$7kKaMsW9)O7VH@KXp$i zbzh0S6UtBx_sG0co04ixSQW|h?x>`|2jPD#gY)2)DRn(k%5ugos4d8N+`W5Wpnp-T4V6!iseD~V^Pcq9Z%EK zI*p5}ebF_e_6Z%3DMl4*+Ro5O-MJUvl`EvU(s&%fY0r-g2e%1feA!M=YhOSRcoK=v z9bhjUHeL5vWYCSnAyc=abJd62iY4J34UCM6RrG3TQS0sF3${Phu|;9WqKV3sqD}Hn z$I~N7hoBB`5Br%*Oz7+lw4 zW)|i$KhjSB?DTGmGEyDDaSWUr5dS@C`wZm%Cl} zOr2};HFtis_r2K%^{OpYqy!NkED#sLf{b_8$t2G5PTH8&aB{pN+W(XN-g&#{ zC*9%;dpC3y73H=tD}?zD6_pNIXrApY{Qgg_#}VmSHAg{}p~*S~{KL*ecK(|4k=z=h zVK9<{g18CFXHlc!#}GzW@6!((I-!Q)O0E1_x-=#W^cBJAc^&*ZoR6;jY&5YMKT&C= zuA>ZVHqoSA#w7b!Z#r;0jrMV`I*ZvYB$_bQML`d@^Tox(6`&CKT7h`RgDCsj;nP4)!%N-zME@jv@ge>9~b zP>JaIqeN_uDv<`nxogg2IwNty8b>q4RtXkC+e+<^$FOmXN@V~_=1k%D=-j&ikEURx z`hAuQCtlI3Wa@B#oBjU&9Wo1+kXAM`Cpcan&A^(KqT{hLbR7(1PVW7TF@wsw*qv63 zL+^<(+KmK*PgfXaGj!AO%r^CO%+f{H9-}>y$ zeZ!IugJ&6UEG&v(hL808=o0<6FeR2}MxHI@&neZ`5lvXuBVp9QmUT@;&$-*MjWFN9 zAT5thQl{v^*^jQ0i^OSYU4GPc;J(PZY;Su)&DM3}f7xl{&$>iVoY-NlP8S~(M|0-q zNTZjow|AUyf-gr`brIg_FIYl+FML~3hy$CIi<8QXJgf;Q=&Jz*ea%(0%Ij8DfTPD( zZOUmMeg$y!U$Q_uz{eYsf|m6rJdGb5{rGzIo(_bMc~l+F1pTsI_Y9z*C(n@O1S#l^ z3qre700q4nhlK=|_Cz}tw_Z4=QJ3{6)mOVXk*7i+@zr;Lqko=Wf|Uhu^kc?)a25=> z4;(!kMtRjVz|kLe)M35HCct+sr!*I(aLe|DqgGJ>)rcRkOQi_|pr8lUh;3zZ^+r^u z59?~=6}>Bk@)KuS2L}PEg0sl$u*0v7TlQ#y)|BP~FNihzY?CkE5J1hJ*lz#Mq%mB7 zm@WkdAsCdu#b5xHLB!0`)WYe_n?H+0^~(_p0ujt+vHp9eQ)BuRD$5tWij2>p9!IKX z9(X;ens=n^8@xDo@-U&Gp>CYZA$8yCRwJJ=1)|%7ZeCZc~rfnOa?zPF)Uup z)-nozXoiefvsglbSk_~RPgMiB)aU0?ZpCuvOn0i66Gyh%D7Gkj&`g&0gU<b@{3u zhGi>|oUjuD-S=tEt=b{hn6jW#wW}l21w?xiL~l!&@LXZdI}zBAc97#Ey;QYI!+MMdE?HS^6Y zan`RSuMHA+(jTE@tbNwHA=|VEU*+BQtU_!MSkLgTs5gT2EJ+zbE${UFw5scSm8KvW zFLj!)>`Lg&(slT$88%;SNJgtQXb?WN^g1ftQF1mJEur4+Cm(-ccwsR!Ip9R$3myfZ1y}@2>}#)uGkreFpZTO6%@Rrj?ex=en-J>E6+=4@Pv%`Q==x; zp6>P(Kyl7wDf=KwY~e{*mu8O6xcg|h8LEHTEZz-!r@8#xG=II zMP!lCJi0Z2<&mc@$C{&*%+3MV{h9up=wi4oz3uS1ouVN5hRV8Tp-(8@?e|caYPW_F%w) ztuD3GMsBU>eT(3tHYtoe*ylOOcRKSHE#F?|#+xF~#@TMZ0|}u2ribmhuKYj`|Cl?&9#nh&w#Zhfj}p%N zghM(&LxA+%5YP~i^B%_~saWKfOHD`9mS5+Of;0qxkj3IkM|4^(E=HuOvdVFTOHHUO z)!^{j*5|V11Z#-JK_DMvxI@8K6rU!GZR`1nlgY4#d>4DwaR^a`Sa7A@n05i($(i_d zh7zF%Xh_#eW(4HVHa|RU>@RHT)k%f> z1eO5Jmjr0O|4wkgU&O~B&G#=buKJ~n#fC6$^UGZi+|QeVRWyXC!Bsdl2!fdn=nXE9 zeCgQJYC3MD(yT-{t1;C^RSSJ-Dqv9Op@J|Jw{sUF*mksW@5#~}Oew=A=&We10}t@F zoLbT@6WKMawpoau@?p4Rb_eq+pYZZ9Fq(~p&4&n=zutGF%YIh@6N#?7>Np^EEj5<5 z2PtVAJhSZZbOrYHVf8GGw+lnlr^d+>LhAR_3wAO35J?(!)rKxkL2G0x(q9hCMeS#L z<4(FM!i_l_2I9dwj3a?=K&5VKx7@OGaqaA$_lAc}8)xXu zPh40|%j%0pzEU>_wDKmm5g3(0a-~kgxnCgMXd3O1AD4As4faPZ_n$5GqlY>$*sd7V z%)Nc%Sx4Cr7C#ApVB|X~ldiZ<^*s2kVrEZNPmOYzWGOZBWe1}OlG5e2TO4ugAh~tW zqZ3c?4Dp@EaSbADvGQ6axLWPEV7fzKo7y5zzKq*X@=Qu9P=rtTYh~Xa1I^b2(n=N& z)O^KINQxUT59b#ins4oNl5{$AIU1etWM>b{1vMWn0RipaUbwyeL-SRUyq=?(;0GfX z?ig4)7aKi5Y=v0`v%<6Y=@f#||JsWBNTZHls5J^^6M3SQOCtz{|OzlL)vWu!z6%;ak)p*naoeM3%;kxI#K{h7aG zvze@stK0*xAE{OC$>-5+Nka-Z$woTQETV6-!;mHB@g3l-(Zpe~56zbeXufbCN>`Vg zcj5;^VWFO~imCw3w?_S&Il9%m(Qw==woGUlls;STBUXe9m)v4hjLIf$)QY)&^%23^ z@V5{x`*^X$Iz@}#*znHc)lb>VwqMp|WbLkzV&I*$e*P>vhbUBLZxGYM5Q{&IYS&CD zIs69G_JG}Y%1D%%GC(H1fMe~<-M({NKkAulxJo(uo7(iPcub1~zKQsvSjW8VJoWK{ zA%YZ0{VB0Wm_+05UO6NmSI0N(B^Han#p*gsSBqSS*1S@FSvf@yNst^%$|LPqV_h=< zHacmf*1WBDg22PgB*rL9)_+9XuUTYyhbh6wc$(lIu;D)x#lTzaI9-5jse%IZUcWnD zFBgAoig?b)(vg%MGpr1P2Dz^n5vMXWTg*{SMkw>DKRZUThrE)$muY4S!F^q#!=Z? z?t#RJeO|r3o<3<$Q9yPlXOBrt(3W6xuDUtkQ1hervJ-fCHS!A~wSpH`N=&x)KJ?yX z7taaQg*y|NZn;mP?JrJI>ek&i{ajL{7F#N7*tq@2w9^VvM_X&&9<87x64;-%q(+3j z_JSzdoNDzS1)Ew^%W`$^1xzmO;ur7Mn=#wF5X7K50VP`u^QPT)wFcRO- z-{5zM9g_$HmP$L)Z@d?+#f2qu#Et|7mQa>K%MEyS1R)t{7*8KBp?>K(S;$}*JYV}S+4%@n7MUp0@| zebISskl+xRLPIxSXuyxbvdB-*L}f!ycd~&)tMOA5y}d)y+%`s2UsT!}^#$8l!W&F| z@hbnTP8Xy}_tm|kEN-0@kDEVQHm4|QC)a+iEP`Q?ja|J$a9dbqU-i6eV(+)oONkOG zff7`EjE~6O(!IyxO**^E;Yc##=g$$j$4LVyx;bkl(2w{lKO*m8i3r|WfxX3OG=HvF z;V&MLk#{N2iv+#w?%k_E_{od#^Pi5&wLct{SeHK?mCJ+$HlAqc!jTt%qjFm4QBHts zWA0>@En=dC(6KQGdoEtDV&M^+oB5nbY1#0-=mh%Lsr&(Ds*(HUQ!`jhnM>EL);7Mc zY$)I{H8ZB)ZytSvE(NzpJ)z7+#1&FpuDE)knlv9; z;CRZ67~wVCA!~5Y{C&u6pnhzh_VesWKBhFIaDA@ivV;Y*wJ+jg2*GQXXiHzp#puIG z?bD{D^5&>6038+dCP+t>-wgJLjw&z=&`}kRkb0dNP_Sc&EsM|vsr8)J(SENyy<>14 z2wc+l{b*dD*1*R6RI`lS@I-`vPp6dkY#)Q|VFWe!E|^b`F=rm&lC@ z4(Q|+?~^`C(j+-Y&viey8X&7ow^hQ+F%GGIGBL4x1%<+uFZWG}LHz|41?4i|>^zO? z(4xf~e5Jy&BJXpOU#l83bcg(Z;HmsCRqcD{fN(o!R484*YC|-L=riEGp;{^aCT7RLkOQt!v@|yc=;K*`)yJoS^zmYVK7J3- z$D92Vef)@P)-p&R-xT_nKK{u+>f?+4l|CNjK_B0|)t+YA#*#J*n0VHoozTCu_gsN{ z$s-g4ApY+QMtDAZFMikr9RC_xcOT8&xGy$P3ca8}z}~RKD(42=A-SAyhZR>b1x8%= z1+8PZPP+BfYDEWYS{idVzajyAwevTOgRMd>@NP&(E-b<{*0EOGjZxTO)o&WguUo@T zNHruCngn&XGV_#IPcueYj~}VtlYM1xt`ssV7N^Nv=1^~b$EBv2mxg)RW!qI-eS$HF z-~cvRuo+2}5()n%<^uC9sy3z(il(`}ozV(N#^~!8aVYsXdDJtHLeSNhcY2w2{18#V z!=@V+7DV3Ig!&Y{pu*;@*yh_*0>#e702@ktY$-%gGKP;tIx3U5qQ0;8$blcWo(0Pv z2?e{bM==t1dXu!VJ==_DEMa++3k%`5zSehHk897f@9K*PO|PsDjp6M)g{WRL44qqH z7M8bN{1!*1Bq+5V1%Uq(z&)_GV*)t=eQv03hRGYi7o7J$Z@eE3b?j{CWKhk8) z{xBw$cA7f!eN=_2opfRTiL%f#Xl1S!uUFUH4M(cI-kk3kw(iU!=)oT_hT>|aXuqP7 z3wVMu=y3_h%4A0+A@< z7&f3tlmxnGSKIcBh!k#u?XZ&XBi(sxanu8whG@)>=0kvU5WB*TdD4X#Sy~0I%`GgS zVKPGmw)-wFHaZ0Bgt9a02&Heoj#-zl;ne3*PlDNJ651K(hG)t9A+`P%T(`9lE@lr* z@R7g-|L+7+{sm>*=lU_>`3Bbq(IhioUVqWWWCnmQ`EJ zFTw}9DHzaA|I=#rzuQEAOzlutqFhp5$Q!M7$#SK}5ATIg_@ge-l4jc0@m5`MQ&IFH7uzU7bk z>=MYc^Y23U2`}9+WZJ<17nOe(dc0THG%C1nW@y#)5NB6}v6jkQARFqObL!-we{SG% zdxDp-I5!rdKAd%TBMj(uIv(^oNK}-XKNPt>d%wN7VRBOw3t(iw1zsKJ-x}F}M8Ezy zsHa8^NrEe2_FT3%cC^I`(I|xkg0a65LBQz8#zOP486r6ATBO}%D3K}pz@ATu+7@%N zfj8W!u*Jpp>T!&b-AL2@8Mk&V+6_ameQOiJs`+XFdZE{5vk|Ad=)m(yo6#D2xzn3G zof-7v^@YK{4ltvz5?}S)Lp8w{b5W`cSlhXAV9Z}`Y8R#Z;syO*%1dV2^fdRJ>aZxF zTx-hrAJX!65)rOJ-g0z2h{at$lbYTz0}cMFiHYgdvo&zAYx&OO&dLz`f9INId+`g}@(qHsA`)2$NHRi?EgR zRfZyU%s{o_gzamkz)aNjOxP>ItH&1-iy`Ud0TAF0>qf1CDX@)kLbn+U$YIfoAjIy@_M4JEly?t~Ul&j4 z;D4*7;Qwv$n(=A8v>J($z(rnl1dW(j9d%qFaaoOFy&HM=;Pvd1+lKT!eFj6`1lf(mkt$$Vj@% zGoI>7GoEo~tTR>dHMFH4RAN*|c;ctp^cE5K2}cW8X=Rz(l>Iqk**UuKM9)+E9*@SY zQi{f^x9#Ecs_K1ta+Q8fME0#cK~J)=4_iCE(o;KGYXz$TpTYCpon0G&AxB=#5mO|Y zUidQz&dg;Y&KUji*e}k^p?e=L1mhd?w6=8wROFZ;uM@U9(!bMuT_0DU+h*Hn-mUXR%EacoN2B1EW3Z&o5W#hBdqZy zlUmpw4c1wWH+;{X?1gW??#dF8_ISz0h-EMfVAqY_5q0Z2454r+J)`XHP{I z?kMQm6HBzt^Er6yr(84A=s~XO*Q?i4#1F_dDc!%xg5;VtYTDPtJX<_nO`8Qj<(fr7 zcZg|lvqqY%K%A*hURmgg%R8xzX+W;&rac45HP?lVygSbRQLZU93rB1q@gUa}{3+K2 z`ytnCzqH@{FLKS42f1eOgIqHjkZbZj$TfBUkZU@g2oYLofU5seKHXQCAJxAIRQ=!Z zbJF^w$f$kL*MqWPgaWF6F_32ZQ2i^8*V=>pEwC>H5h`jE zyAEEvTx(ZpIQX*nXLCK<_3O833E0b8S_-%msB0dJc;!5%yCf4<^NkwixgS^Sm*~Sd z!<(n@DziE_NWUV5+F(>K-GG>s2;k(^i@#epZ2k!qtSVyyXaJiCzL8+38^{Z7k3~rF zGn&C4RA6SP?b!x3kCuYh%}Fd^zB|qtB~+K3&_Xar$Jpo`25}#$uS!f`g=sX%lh7UP zA0{WVTi8!YW_pe?A;BW7Q=x78i4(V%s~fL{as&qSoC|RWV*~`JYJheAa&HDk5I^}qHB!4kjXJ3tUCkkXTl%ttd2Eq;)!8pzi?m`d%2ZqzB{XE(WN73` z5#=@`HzRp~kv;jcN1QO%A1^jLQuwR zoSvEwYD^P&fxSoe?NO?h5k9qe8tdhE>X?>X35fXXz1Hu(z0lU#$SMS=J?fr`1a^q4 zcZ3}7NXe(U^OiS5_m&dK@6xKI@o6NJwbM#+A5Q%Y`w%10?NAzwQ3JjoW9^uVv2 zKBzSB-ksq++4BtZWXrq;QoQ$h&RIyWnYR?0$gPF3Me@QVBUuO7-8kF*e(-{AvHuQht;7M*NWXCV}L=bmKo;O8r05018&WMw*D*zAjm zQU61;HI$U3AWoQXK7O2C;6`eRXyH7q=*P$eESW3RY#dos-1#T|xqKU#2<1NbWmF$$ zPv_&mE-VBE@`=NQfGmF8po9`t+p-Eh|1 zYRU-BuAGReU}NNZB5na^bu?3im(V57ug`Bn$v2H3m`Fu|C;0cArJ(2c=Sccqu}u=< z8EO;bK0hLFb$P&g#b`*N);p-O9P!y~@^YCt8JhFyQg4{CO4#p01q|5Lw@A_a*5gwj z<*{sfeK&`aFAbUd&ms5eV&5TJN9_&@%Hb2Vy?U3UN(bk|gzF^FwITfq&!Yo55iKt% z;PptZtvGa+ z8`hc)CYl=r3_F_jobpu1c=7L5yNYIoCllTeeK&M(CvRR4zCb#`c5ziAW41xtEBM#~ zSL*40r@V?L;0Z}LYa_?Lv>zd2m~NeK2N9xCyPXJv~i@K3#x4UhH`lglE# z+E$`DG2A;01<+;!r0tD2*HyL2M{4x({KTopdXJ5X?eKYi8~~DxmjM=Lhh4x7PqZAB>XNv_*DRbzpep*)q{?dJjC!t4@n9FM@lZe zkC+x!yalT;7nLUqQRYQ^EsqR@Hc|%$Vdo@i-$p7ATr_#cu2+B5S{o#=>o%dlfs$cd zEW5r+U%5_a$&*wKDiGr-M%8+s&AdsF(40NVjp z=dw6Yl=tmdP9kwJ!8+XKXHxMuItjL!Vjq0;QOFQXAztsSwI|F1Ts&|^OgReYjd~N^ zZ7|eZ=sXsdv@+m7M49$m0evgWtK_OdWkVVoMJpTCyYwKI2AJ1&OFmPf6*}o!e15E9 z+_5wt{ORXrCi;_o?boGV?Ly}2nP|Zk6ck`p>K~C6RMz>70H@1LsJ}lmqzSUAY0vU) zA-PyyW^hjcFHNxMXJtKlCOO6<2(wUXk{sgq{kO+q=|I*1A`T&d$MH85sHSgp?H>*@ z|CXKhi#u`iVK%ACd+w(tgd9>O5f73mApP^%go=gsULiF^s^I5ra-=aNkqHxFSP?8M zfTWk2eN5NSGyBqgx6Oh{6m_hzRyOw1*=KN4#w&w?O=W^SgG!R0@DG436~7$xYSg1{2#`Tz&F|Pm^ox zZAE4qjKjL2!MGTFLWCle-^%a-IsNRiJt)F&>LJ2!SsY`pw-w_3HYA= zx@ms}ZpTc3ZpRog;6GbZdrm5%@vRTwt7)BA$&redfk4M%N(Y@ig)AUI5_CI8`*=9C z=$JtEBb8*XX-3dzRP-k#X~H2dTU2%scF)cCUgd+{?-A zrL0uw0ziZ{8a2NyD7z1Meo|+B>d)$d0LfHvDMy=!8y@`?iJm#t=9VDBy5#NixzW|8 zB`X%@9SCx1@q*y-vMtaJk1~y}!`C)IY`R7&Y?-gDN@kZ-&Y4 zJjRh1biU}aS`9+c3ee&q5OF&9GHekV0 zR0;w`UiD_nEG@NLaIj+7Kwlw9*?5x=m$Q)pkylu&^fiXUEf}U&qOSnUC95CbI;K>) z4>Tin<>G05JW|6#1xXVIDDsMW`eh?o8cXrcvd++t$gAfni6fm#Xt$UeK;+eoqh3a} z$J0L}Oj};yvOb)V`I3n?@m>U|fL-aJ3YZC_HD10;&k8yt15-oH3fQwBBCnv124^24 zuh`?T%QRsKaBT&?X!&Y19)y-r4}-jyb;w3z#Kr~hyHgZX_SiIQv%|{XuETKa)ndK` zyqD8Iy_cMScrS~wvTgzIC3U&)kKp?f!els5@I5<-?Fkl*MnYO%AYvzr=96#tjVYwM zb2bNEFREABUuMMtBCn=`jwK(wm&#n>BHz>vxL&pq@XruBmH&UOU3WZ{Z`hX^vMMVx zJK1DLSs^=nWQOb=QW+q{8Bi|InvPMJ~pMP6ow*e%nS>}3trYW5HY8#aK8+y4M zNej$^CxGQw`p+|ed$ZtS?Z`v(AQBE!E1?qaJq}Y%s{E2Ux(!S@jVuz3%tu!Nnt;%d zx(7xE087AQovC(y{cCU$t%E3(Z8>(s;|yaHA>Or29{0FU)Rp1BZy=?S&wp0&h1~eq zwA+BRVM)CyM}qNUk+Te4&CNY!gFk_w;D>@>1CudsmUmeOQt9?5s4? z3RLyCD$4tqmP*c_8W(4ANu^6TkYAu&BEoeJMi8%w!im?^0OBoS3IPuzr zTXp+UxKF%BMe}Blc+Cxn!s~G2HSx*h0E$ZcuzZ$x@D#zz-6+fm8%$J9oa@yuO%2bt z{3x&&g->eU> StVlxlqmaiim-y8bz|wv0g}1;Xc>hr@CVe1z2$#-@?LHI&G4%J;XC*Ak9&p+W_{~) z>7eEau)ddGaZ-Z3!{E~^4vnu2IMUO!VxS#hfT-YIcnBUbLj?~v`1|O-lEq0lonza_>Yv<1$O-c`bAks%{N=tF^qH}(Z_Wgm*I7) zds14WK%J@*oX2@jN~<8rdsj+pw{C1-N()$qPhkMdFd(Hhd00woc3(=1;#n9Gnr-w? zC9<~>%0Pn34QEDJR^DOpDwd+5(D2f?VJ$%aBmC?dp#RZiOba0y0p&;gud1m2KSkgF zwg3l_G?dI5o7qF)EaLKvql4(G=o+k!;vZ{yU)lkCKvy_J3NZJ9DA2;MT|j@xxR)O7 zuI&O83OuGM2n_t>H-C@4ws=Wubu^&0C|nkOGa+f^tqwv;*04-ACs2ZkQ#2dW+D z2euv34+Qv8exn}Nsbs@@FY{(G>RD!_p`nl>eqawM4D11|w;O>y z;J@?(tr7ZxNeB9Y<@@@9q`&G1?y?^o)(?cUAAAf4*bgdeGR_Ioek`hlIM z06_|0!TkgMz#;5C{XlrV#esexumY>r-rv;^++BhH(GLXJ4|eqft5pZdxI3|&74q*hUU$iQTwEde5Aw-zm8XTopE=`6!d9`blcW0cGljpKh*7 zZZb^Qe}YWnv>zd)is6(Ntxw#y$0z)+m)2NUkG~z5J1M7vQi|+u1$IaIefwbp8OM|dA*q+!yhlD<^GvG?uNO%=Y z_;olb!*#1%5xP~`yNtDxn<8-CDsgj>wl`RVPXk^I%`aX!c4r}5`!=EM0yGVvPpqdA zEIH+gzaCg7+DK`kJqSNrL0zJ@76HyydV#YQfsCbC_}PlH0|Y0Zg=h3@{G;y)z}bpF zTm=%obkPJ(Q6f=+++VujDv)dfdkO^Y8ha{`p^gr{fC{9@t_oz0b`OS)IG|f)(qqj! z?+fTw=>xh|cyQe+pyFAqzknC6TlIyK{X;QTPHLY5&zed3>#f)8QIl~Z%-!dv##w~v zFT|)0@WxM75>LI&{79ku()^zU20{fAc!NB@)%Z&SBMO|r5Zp~*$m}LCnE#!?_`H|E zkWb3cZgZ1N595+lgjfs>DeK*L$xVO8SDFraoOe={6$syDe_S@1q9 zOn(da^q7OU^{Nq!#qJ)eC(T)9iT0GI?o0`6SbEpi6xRAi`?}sUOMN^cPkC4TWopi# zjOX$Phoy5IEn-=Y!ivif?9Ag$QH~D9ZC92Jws#zs26EWA?N>Wx>@MVGmW$S(@-0tV zc5t{X)oRIZ?7707&5(Ix#Y0V!T5j?y$94|~U-Z*6u4jSA+j4gE7 z+0wwv^rYUiPdkIJP#<{oMmxwk&klWSDX>p8NhTsM#-&RSUOq{>LNvY;HNtHa`s;#!sj#@x1vbaRZkVX3Sfv)eLFDRq{;7kN<1X;DmuM78~xL-G5psR zvgK;&q3bV}bkxF)L|uK%@RK4tFKhKuYFW~fF{`$=Ms2>;6d=bui|Ua>j}xpb;DiI^ zH09B@?;0yydXxC+{zFzgqPp?O<1>#MzPVha_9CNtrP|z$zNFP17ieY3E(RG;YcOU> z;#889fwX@e=Ea#6D9pH-jP=_8hS@j)D%nMqA49iqzQ(QPU7c@=ZX@U58^KcalaH^j zTVyis$C-`W$Y3(C$9Ajhxj8-H7gztP&S8mqkWIkQK6Vawy~=mACgJlcdB0NKvUwWb zR6^6zi@V1JM#;Y1#^{44d~17{vhei_k$a5>!Q|_568Nk@2J*@@JCJ=N?;6t#Q7m zVi*`!=DPNhzN*6#kfU|KRmurDl}bar=sCaL1=)DTj>Drz+b7aOTuN23vCJ=#X%c{@ zF_$k8I4p8rzQW5m##MscfU1@>R*!f^!M@Kb1I?ktz2sU9bXky7J>sM*`h{%V=wa(o zh9IBHA64n)ZiO~FUplhtSlM#3%s7-eY+OpUpj|gG<~(N217jAtSC@H5q+W?fF_>J% zaTmzYAuzlyb$7&!)L=ZNAWXzgac7>aDp&@znb8O5|0aW(Jdyh={$p>bzpk%bekBEv5&+iL0~ zOWU4l&+}zJd>1yRLhsi-EiYy^pRv{hd#;5*WmM0UikWi zJ}@uo0Uzc+nxC{}rKJ@x>bP-Uah<^ExDM^;Kf!~YR=ke-Oz+&;xa;f1$LKM1sGYW| zOMiH?p08YZ9tY)nkA}l(oLqKxlgPYe`SUHsH9q_meq0ZJ4_BFyOL4D6Zk`)`()*;+Vxf|bv| zZ5c=Xr4kcv9vvs>4nHmm%2Nsy6qY|Se@$9a`I=O2Tnp@p?n(ctH64Z!YRYbJrD#oI zRVKF0YAmAU>Wgt}=9cj~9&a@0WAQ(Ji=bL=!dG}AJX=*TV=R!|`qeNmp=V&a+;Gs0 z_bGMg_|GfYv0a0S!(IMZFDKIqk0}^EkqcRQQh&OP*d{>cn(3ep#ZvyK0PlOeVh!~c z0&Gs>-boRi%_CXPi=~Y1g1#bFx9^>>x!LHf<9Nz%u$I=h@;+|-ZL+G{l+?aX@_8ZZ z5sP{(48l8Hvs2HOLFKy48weDpLFD5GMh}Icx<}fVBM9~=vn=7bu6`*gohvU<0 zn_be#rnG6H8L{1TrD4;AXLii`9}F$5GMdo1s_})|5rd`3g!rt?zmH4!G1OpqHFgmwQ>a6{77)m`jwFyp0=Sqy~V(aQ?$%nXl{R_^2zx+a{F%i8Z6ZX z+DFu^vzVO0p-fxp?c}@TbZznB%8yjyt+o}+PxFAE~Z3D z5f-C!fhcp!J#}juXrGhSt(ZL^b@_@LmjVsdGGz?7%-tS(7#Y}ny5l?4YjDHi%%q-> z8&9g^9ZOx8*zXO5&CErVKI&KkTwhzF?{O&toE{BPCi4_Ew!K4(FO<0gPR0(&O0PK1 z>e1x+NWJp7-qM|OI{GG{$9kK2@8O5vgfaQ|z~IE)s-s9T%k)mvi1I;i8H^ukNL&usEo#q?41_@;JNd z8Wvak^M-LPTQu9VEA5Y2j*D@*iTf423z91wPsO^Z+hcXh)#2nxts5#iaoUtzu?_Q@ z-W11~ybO6SS=29~@m8)b52wuAn#!FlWtr?(Teg8VIa;zA zZ$NhXYJjd1F=mXQePWK|mqtLZMoVUdiSg4S*Q?xHiqI!(i?v=~_-g9KEc$EG?vHJK zh~a)slKrRwJR`7(*K<#Dd<9_}*>k_!njE91{EWim7+3l)tpvVMl#=*-?s z4nmpd3ZGr>_3!Gy-3n2Bv~uze-{&twpP+9nlCnR9Z=T5hXhZhZ@(l5p4{5C^=(WaJ zCRCa#*^#Z?IkKN<60_ny(2NT_i%@69jb}BWdKCGbim^E^Gu&3wmH*2dF$>6QYyren zOLC`jz&Bs(xw1scGgNwib$4&ld(S`f2r=Uf*oqSgzteMoO5{nJIli#%H~RTq_R>hk znsVpb)lECtX!YG43{hKeTCH!WNhCLd|-u7cTVa9Zy8{bSJdcO*vsr5-!eDVJ`D&An;v z*0NR8sb|4xo{PQC+n|vinuI?qJ;B+dBvGq9rb_3Yow3Nf^(tX8!XoUNXRyfi^3j5z zv)osre2g^DDkWKeyhPaiV&q*R$W@#DqVXhad|2ZB|R`3{dxa$I$Gq7>Yv+f|<&wYE)X*Tqj{Zj-Ee%N_W7IJpaJ0 z2YN&4Oa1Ma#%@S^;eoT!Y zLg1HjYeZ(O%Z0p9h?H={UyIT^2#;T;aEJge_PV-7uj?nA@E zk&iiA_|C-$l)NJ|xP>lFJjFgkLRTs-yFw6m>BReT3ySQ)IEbCr7QJ`ToQ;leV0U+n z2q(W6-9-h6)V5g7=!&n`ZQklmCS+N%sP~e>G9Ydy-C(yMvs?<3N6!+ z3Ki7bXsl+VoV}d=lGLf|VG3e7&E~|aD#k2oQJ+H%(%BdST^7HI8W{{{mU%9$QsuVy zPo1v7vb42d?tfcScipzRA_F$oS3D7m!-tO*6gFNmx(Yj1?W$DGYi-J=Fn>`-W7Lr(s4tun6jNwLiwPw`W5bv8<+&>V?sTWZD+y#;es@ zM`2LX$l^Ai!d6v!y>uVq`qY%%2dqJ)HR^6t#njU##gMFN*jxYFQK9!+PU{lZ71;Rh z$%4A_cM3J-Rjy3PQZ!H(MYEwh%3S2Q@71WM?aEHSz60NZp<0>>rt9IrZh` zb?Og7nr>NjtcP?J%cZ>GFAD1-5TN_uSR3(ntuGw?LV8ZCkzdH29w=#OPuiJ4F28dU z0^;Z2Swks4pb68YQanZ(jT^hSy4Q`v_+i%fS(3ZJ462XX+q3#r@GZ z^+R$p`S`(Fk#ZthtL}pyJ|40qwBifq5ToPU*!QcZ1ZOJRdWVuSho8{n2bbt9@p6;8 zGg5Mtf=wA! zwoaFK_DM4OO}mecMGZQ-&ZDTy$|^45s;;++Hs&s=$R9&JjRLfOqZ~)cwl| z3BvDhXgt3DJuqfhff3?4bbn31x3_235V%_j`x}O)fE2LHZm}8Ye&P0++XeiTf#)a! zw9Z^OWPj%DZ|@hG{e2z+BoOziglUw3M_vRxm%}cEFdhj4uBDB{e!kzO=`g@PB@pDi zhg>)Zyt@8o$Pc^li~JfA0LNQ0c*VdoC z3UY81g~Ys$pM-ZVVEQ%?Sn&Ds;DY(Y0CD_(`2dvt+Buv3^6i8B!@~tX?fP|^hJOh$ z+%VnYMWhGhxd@;H;5+$OKzj!=U?5!-JM~|s>=8hx03nyZ1KK?{1_OOkCE14Sy2b#D zn%Dsf@Dt_}48-@5fc7Vr-;Z8$gLLn&JYffLFdu_Ue~*QH03}{jUcv#UOH^!dNc4#x z5eq(>{obhjq5%!+BLxLQ-yXSF zV0~)@6u!bAL;c@s*I*C9a>fYQSfxLP{be!QJs*cR4uFBcGNT9}3$?!lLOzgSX-Ndo zu*M$)0ju93p-HeeVEw*dK(zk?1i2?*(KZB#g5FU<5S?9MSHRj>2o!mPzd=Fn3s?^c zfl_7kS13p)aj*yu0)@l$NGM1palj)77IHzL_22j}XvjwpEZc!V)3!JY+ChgY5aN3+ zK47=N#P|pxLz}+@Lhccm3mpN}WA`^ezmIV+-7o@a*!d_($jFDm!v`h-MPL=W|2-D+ z5d`x-BCyVT9tCTE$8ycg*wn=m*aZGQHbAU{2tew){}B+mhhUmH1Yok)UjY8rF)#rX z0>|e5-{Bzl2Tc2e!1>^R6dVu<5I6|Iyfg@yr-4U-0qT8!J7i$S6a!;g6BvFH65`T>}GxTayrgYRUf< z5b0hC+=zkz>`gr);Njc~+-u}<0&YA&K^V Date: Sun, 12 Jan 2025 11:09:59 +0300 Subject: [PATCH 219/296] refactoring --- src/generator1/logger_setup.py | 12 +++ src/generator1/pachca.py | 156 +++++++++++++++++++++++++++++++-- 2 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 src/generator1/logger_setup.py diff --git a/src/generator1/logger_setup.py b/src/generator1/logger_setup.py new file mode 100644 index 0000000..713bcc1 --- /dev/null +++ b/src/generator1/logger_setup.py @@ -0,0 +1,12 @@ +import logging + + +def setup_logging(logger_name: str) -> logging.Logger: + logger = logging.getLogger(logger_name) + logger.setLevel(logging.DEBUG) + file_handler = logging.FileHandler('client_generator.log', encoding='utf-8') + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') + file_handler.setFormatter(formatter) + logger.addHandler(file_handler) + return logger diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index dab14f5..3b46f2c 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -6,24 +6,168 @@ CreateChatBody, ) +# from pachca_api_open_api_3_0_client.models.post_members_to_chats_body import ( +# PostMembersToChatsBody, +# ) + query_chat = Chat(name='test') chat_body = CreateChatBody(chat=query_chat) pachca = Pachca( - token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', + # token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', + token='MnVVaQqJdjw5iRVcOoYJgZ440hTdUVArjl1idgx6iow', + # token='qW3V2Kw7yxu1UA5OZLCdyoyKFfWA6OYr_MK2WR6PxbA', + ) async def main() -> None: """Функция теста эндпоинтов""" - task1 = asyncio.create_task(pachca.createChat(body=chat_body)) - task2 = asyncio.create_task(pachca.getEmployees()) + # task1 = asyncio.create_task(pachca.createChat(body=chat_body)) + # task2 = asyncio.create_task(pachca.getEmployees()) - print(await task1) - print('*' * 30) - print(await task2) + # task8 = asyncio.create_task(pachca.createChat(chat_body)) + + # task2 = asyncio.create_task(pachca.getChats()) + # task6 = asyncio.create_task(pachca.postMembersToChats( + # id=999, body=members_body)) + task5 = asyncio.create_task(pachca.leaveChat(id=111)) + task7 = asyncio.create_task(pachca.createThread(id=412338865)) + + # print(await task1) + # print('*' * 30) + # print(await task2) + # print('*' * 30) + # print(await task5) + print('*' * 30) + # print(await task6) + print('*' * 30) + # print(await task8) + print('*' * 30) + print(await task7) if __name__ == '__main__': asyncio.run(main()) + + + + + + + + + + + + +# import asyncio +# import datetime + +# from pachca_api_open_api_3_0_client.client import Pachca +# from pachca_api_open_api_3_0_client.models.create_chat_body import ( +# CreateChatBody, +# ) +# from pachca_api_open_api_3_0_client.models.create_message import ( +# CreateMessage) +# from pachca_api_open_api_3_0_client.models.create_message_body import ( +# CreateMessageBody) +# from pachca_api_open_api_3_0_client.models.create_task_body import ( +# CreateTaskBody) +# from pachca_api_open_api_3_0_client.models.create_task_body_task import ( +# CreateTaskBodyTask) +# from pachca_api_open_api_3_0_client.models.edit_message_body import ( +# EditMessageBody) +# from pachca_api_open_api_3_0_client.models.edit_messages import EditMessages +# from pachca_api_open_api_3_0_client.models.get_message_reactions_body import ( +# GetMessageReactionsBody) +# from pachca_api_open_api_3_0_client.models.post_message_reactions_body import ( +# PostMessageReactionsBody) +# from pachca_api_open_api_3_0_client.models.chat import Chat +# from pachca_api_open_api_3_0_client.models.post_members_to_chats_body import ( +# PostMembersToChatsBody, +# ) + +# query_chat = Chat(name='Testing') + +# chat_body = CreateChatBody(chat=query_chat) +# members_body = PostMembersToChatsBody(member_ids=[516675]) +# members_body = PostMembersToChatsBody(member_ids=[516682]) +# create_meassage = CreateMessage( +# entity_id=17802862, content='NOT SUPER PUPER2222') +# # edit_meassage = EditMessages(content='NOT and NOT SUPER PUPER') +# edit_meassage = EditMessages(content='Вот так вот!') +# message_body = CreateMessageBody(message=create_meassage) +# edit_message_body = EditMessageBody(message=edit_meassage) +# post_reactions = PostMessageReactionsBody(code='😭') +# reaction_body = GetMessageReactionsBody() +# create_body_task = CreateTaskBodyTask( +# kind='call', +# content='Звонок другу', +# due_at=datetime.datetime.now(), +# ) +# body_task = CreateTaskBody(task=create_body_task) + +# create_meassage = CreateMessage( +# entity_id=1781540, content='NOT SUPER PUPER2222') + +# edit_meassage = EditMessages(content='NOT and NOT SUPER PUPER') + +# edit_message_body = EditMessageBody(message=edit_meassage) + +# message_body = CreateMessageBody(message=create_meassage) + +# pachca = Pachca( +# # token='x4EhHyzYY2aA38GJb6AnKQXcY716LnEHCoxD1dUEyCI', +# token='MnVVaQqJdjw5iRVcOoYJgZ440hTdUVArjl1idgx6iow', +# # token='qW3V2Kw7yxu1UA5OZLCdyoyKFfWA6OYr_MK2WR6PxbA', +# ) + + +# async def main() -> None: +# """ Функция теста эндпоинтов """ + +# task6 = asyncio.create_task(pachca.postMembersToChats( +# id=999, body=members_body)) +# task5 = asyncio.create_task(pachca.leaveChat(id=111)) +# task7 = asyncio.create_task(pachca.createThread(id=412338865)) +# # task8 = asyncio.create_task(pachca.getListMessage(chat_id=17802862)) +# # task9 = asyncio.create_task(pachca.getMessage(id=412338865)) +# # task10 = asyncio.create_task(pachca.editMessage( +# # id=412338865, body=edit_message_body) +# # ) +# # task11 = asyncio.create_task(pachca.postMessageReactions( +# # id=412338865, body=post_reactions) +# # ) +# # task12 = asyncio.create_task(pachca.deleteMessageReactions( +# # id=412338865, code='😭') +# # ) +# # task13 = asyncio.create_task(pachca.getMessageReactions( +# # id=412338865, body=reaction_body) +# # ) +# # task14 = asyncio.create_task(pachca.createTask(body=body_task)) +# """Функция теста эндпоинтов""" +# task1 = asyncio.create_task(pachca.createMessage(body=message_body)) +# task2 = asyncio.create_task(pachca.getTag(2232323)) +# task3 = asyncio.create_task(pachca.deleteMessageReactions( +# id=412338865, code='😭')) +# task4 = asyncio.create_task(pachca.editMessage( +# id=412502100, body=edit_message_body)) +# # print(await task1) +# # print('*' * 30) +# # print(await task2) +# # print('*' * 30) +# # print(await task3) +# # print('*' * 30) +# # print(await task4) +# # print('*' * 30) +# print(await task5) +# print('*' * 30) +# print(await task6) +# print('*' * 30) +# print(await task7) +# print('*' * 30) + +# if __name__ == '__main__': +# asyncio.run(main()) \ No newline at end of file From 71c23bb9481c6e1fb4eb8cd42f1f2abcd9a24b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 12 Jan 2025 12:32:58 +0300 Subject: [PATCH 220/296] logger gen1 --- src/generator1/pachca.py | 20 +++++++++---------- src/generator1/script.py | 18 +++++++++++++++-- src/generator1/templates/client.py.jinja | 4 +++- .../templates/endpoint_module.py.jinja | 5 +++++ 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 3b46f2c..5fc8c9b 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -24,27 +24,27 @@ async def main() -> None: """Функция теста эндпоинтов""" - # task1 = asyncio.create_task(pachca.createChat(body=chat_body)) - # task2 = asyncio.create_task(pachca.getEmployees()) + task1 = asyncio.create_task(pachca.createChat(body=chat_body)) + task2 = asyncio.create_task(pachca.getEmployees()) - # task8 = asyncio.create_task(pachca.createChat(chat_body)) + task8 = asyncio.create_task(pachca.createChat(chat_body)) - # task2 = asyncio.create_task(pachca.getChats()) + task2 = asyncio.create_task(pachca.getChats()) # task6 = asyncio.create_task(pachca.postMembersToChats( # id=999, body=members_body)) task5 = asyncio.create_task(pachca.leaveChat(id=111)) task7 = asyncio.create_task(pachca.createThread(id=412338865)) - # print(await task1) - # print('*' * 30) - # print(await task2) - # print('*' * 30) - # print(await task5) + print(await task1) + print('*' * 30) + print(await task2) + print('*' * 30) + print(await task5) print('*' * 30) # print(await task6) print('*' * 30) - # print(await task8) + print(await task8) print('*' * 30) print(await task7) diff --git a/src/generator1/script.py b/src/generator1/script.py index ef453dc..f6c14a6 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -119,13 +119,27 @@ def get_base_url_from_yaml(openapi_yaml): "client_serv.py" ) -source_file = os.path.join( +logger_setup_path = ( + "./pachca-api-open-api-3-0-client/" + "pachca_api_open_api_3_0_client/" + "logger_setup.py" +) + +source_file_serv = os.path.join( os.path.dirname(__file__), "..", "generator1", "client_servis.py", ) -shutil.copy(source_file, cli_servis_path) +shutil.copy(source_file_serv, cli_servis_path) + +source_file_log = os.path.join( + os.path.dirname(__file__), + "..", + "generator1", + "logger_setup.py", +) +shutil.copy(source_file_log, logger_setup_path) try: subprocess.run( diff --git a/src/generator1/templates/client.py.jinja b/src/generator1/templates/client.py.jinja index 68e78de..b44908b 100644 --- a/src/generator1/templates/client.py.jinja +++ b/src/generator1/templates/client.py.jinja @@ -1,10 +1,12 @@ import datetime +import logging import ssl from typing import Any, Union, Optional, cast from attrs import define, field, evolve import httpx from .client_serv import AuthenticatedClient +from .logger_setup import setup_logging {% from "macros/client_macros.py.jinja" import httpx_args_docstring %} @@ -14,7 +16,7 @@ class Pachca: def __init__(self, token): self.client = AuthenticatedClient(token=token) - + self.logger = setup_logging(__name__) {% if endpoints %} {% for endpoint in endpoints %} {{ endpoint | indent(4, first=Fasle) }} diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index 5310e9e..40e2033 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -6,6 +6,7 @@ import httpx from ...types import Response, UNSET from ... import errors from .client_serv import AuthenticatedClient +from .logger_setup import setup_logging {% for relative in endpoint.relative_imports | sort %} {{ relative }} @@ -65,11 +66,13 @@ def _get_kwargs_{{ endpoint.name }}(self, {% if endpoint.header_parameters or endpoint.bodies | length > 0 %} _kwargs["headers"] = headers {% endif %} + self.logger.debug("Создание параметров {{ endpoint.name }}.") return _kwargs def _parse_response_{{ endpoint.name }}(self, response: httpx.Response) -> Optional[{{ return_string }}]: {% for response in endpoint.responses %} + self.logger.info(f"Получен ответ с кодом: {response.status_code} для {{ endpoint.name }}") if response.status_code == {{ response.status_code.value }}: {% if parsed_responses %}{% import "property_templates/" + response.prop.template as prop_template %} {% if prop_template.construct %} @@ -91,6 +94,7 @@ def _parse_response_{{ endpoint.name }}(self, response: httpx.Response) -> Optio def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> Response[{{ return_string }}]: + self.logger.debug("Преобразование JSON в Python для {{ endpoint.name }}.") return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -104,6 +108,7 @@ async def {{ endpoint.name }}(self, {{ arguments(endpoint) | indent(4) }} ) -> Optional[{{ return_string }}]: {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} + self.logger.info("Начинаем создание ответа на запрос.") kwargs = self._get_kwargs_{{ endpoint.name }}( {{ kwargs(endpoint, include_client=False) }} From 909135472acdca573aecbd963ffb725bfa75b7a4 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 12:53:34 +0300 Subject: [PATCH 221/296] delete test_results.txt --- src/generator2/card2_test_results.txt | 209 -------------------------- 1 file changed, 209 deletions(-) delete mode 100644 src/generator2/card2_test_results.txt diff --git a/src/generator2/card2_test_results.txt b/src/generator2/card2_test_results.txt deleted file mode 100644 index 231915f..0000000 --- a/src/generator2/card2_test_results.txt +++ /dev/null @@ -1,209 +0,0 @@ -post_members_to_chats: -errors: - errors=[Errors(key='member_ids', value=None, message='Поле обязательно для заполнения', code='blank', payload=None)] - Если передать значение id пользователя которого нет, вылетает ошибка pydantic валидации поля vaule. Фикс = - тайпхинт Any для поля value в модели ошибок. - # response = await pachca.post_members_to_chats( - # id=17519775, - # data=Postmemberstochats( - # member_ids=[515190, '-123'], - # silent=False - # ) - # ) -success: - При безошибочном выполнении запроса тело ответа отсутствует - # response = await pachca.post_members_to_chats( - # id=17519775, - # data=Postmemberstochats( - # member_ids=[515190], - # silent=False - # ) - # ) - - - -post_tags_to_chats: -errors: - errors=[Errors(key='group_tag_ids', value=[1, 2, 3], message='Не удалось найти', code='not_found', payload=None)] - # response = await pachca.post_tags_to_chats( - # id=17519775, - # data=Posttagstochats( - # group_tag_ids=[1, 2, 3] - # ) - # ) - - - -leave_chat: -errors: - errors=[Errors(key='chat.id', value='175197750000', message='Не удалось найти', code='not_found', payload=None)] - errors=[Errors(key='system', value=None, message='Нельзя покинуть персональный чат', code='personal_chat', payload=None)] - # response = await pachca.leave_chat( - # id=17519706 - # ) -success: - При безошибочном выполнении запроса тело ответа отсутствует - # response = await pachca.leave_chat( - # id=17519775 - # ) - - - -create_thread: -errors: - errors=[Errors(key='message.id', value='40864392323', message='Не удалось найти', code='not_found', payload=None)] - # response = await pachca.create_thread( - # id=40864392323 - # ) - -success: - data=Data(id=11008414, chat_id=17831826, message_id=408643923, message_chat_id=17519775, updated_at='2025-01-08T10:32:47.205Z) - # response = await pachca.create_thread( - # id=408643923 - # ) - - -create_message: -errors: - errors=[Errors(key='topic_thread.id', value=110084142, message='Не удалось найти', code='not_found', payload=None)] - # response = await pachca.create_message( - # data=Createmessage( - # message={ - # 'content': 'Text of the message in chad with id: 11008414 and reponse to 412721137', - # 'entity_type': 'thread', - # 'entity_id': 110084142, - # 'parent_message_id': 412721137 - # } - # ) - # ) -success: - data=Data(content='Text of the message in chad with id: ', buttons=None, entity_type=, entity_id=11008414, parent_message_id=None, id=412721137, chat_id=17831826, user_id=515190, created_at='2025-01-08T10:41:23.000Z', files=[], thread=None, forwarding=None) - data=Data(content='Text of the message in chad with id: 11008414 and reponse to 412721137', buttons=None, entity_type=, entity_id=11008414, parent_message_id=412721137, id=412732537, chat_id=17831826, user_id=515190, created_at='2025-01-08T11:37:15.000Z', files=[], thread=None, forwarding=None) - # response = await pachca.create_message( - # data=Createmessage( - # message={ - # 'content': 'Text of the message in chad with id: 11008414 and reponse to 412721137', - # 'entity_type': 'thread', - # 'entity_id': 11008414, - # 'parent_message_id': 412721137 - # } - # ) - # ) - - - -get_list_message: -errors: - errors=[Errors(key='system', value=None, message='Действие запрещено', code='not_authorized', payload=None)] - # response = await pachca.get_list_message( - # chat_id=17519775, per=10, page=1 - # ) -success: - data=[Data(content='Это сообщение отправлено из АПИ', buttons=None, entity_type=, -entity_id=17519775, parent_message_id=None, id=408643923, chat_id=17519775, user_id=515190, created_at='2024-12-24T18:00:29.000Z', files=[], thread=Thread(id=11008414, chat_id=17831826), forwarding=None), Data(content='**Dmitry Kostin** создал канал', buttons=None, entity_type=, entity_id=17519775, parent_message_id=None, id=408642003, chat_id=17519775, user_id=515190, created_at='2024-12-24T17:51:08.000Z', files=[], thread=None, forwarding=None)] - # response = await pachca.get_list_message( - # chat_id=17519775, per=10, page=1 - # ) - - -get_message: -errors: - errors=[Errors(key='message.id', value='40864392323', message='Не удалось найти', code='not_found', payload=None) - # response = await pachca.get_message( - # id=3210 - # ) -success: - data=Data(content='Это сообщение отправлено из АПИ', buttons=None, entity_type=, entity_id=17519775, parent_message_id=None, id=408643923, chat_id=17519775, user_id=515190, created_at='2024-12-24T18:00:29.000Z', files=[], thread=Thread(id=11008414, chat_id=17831826), forwarding=None) - # response = await pachca.get_message( - # id=408643923 - # ) - - -edit_message: -errors: - errors=[Errors(key='message.id', value='40864392323', message='Не удалось найти', code='not_found', payload=None)] - # response = await pachca.edit_message( - # id=408643923, - # data=Editmessage(message={ - # 'content': 'Это сообщение отправлено из АПИ\nОтредактировано в 25 году.' - # }) - # ) -success: - {"data":{"id":408643923,"entity_type":"discussion","entity_id":17519775,"chat_id":17519775,"content":"Это сообщение отправлено из АПИ\nОтредактировано в 25 году.","user_id":515190,"created_at":"2024-12-24T18:00:29.000Z","files":[],"thread":{"id":11008414,"chat_id":17831826},"parent_message_id":null,"buttons":null,"forwarding":null}} - # response = await pachca.edit_message( - # id=0000, - # data=Editmessage(message={ - # 'content': 'Это сообщение отправлено из АПИ\nОтредактировано в 25 году.' - # }) - # ) - - -post_message_reactions -errors: - errors=[Errors(key='system', value=None, message='Ошибка выполнения запроса', code='unhandled', payload=None)] - # response = await pachca.post_message_reactions( - # id=408643923, - # data=Postmessagereactions(code='no an emoji') - # ) -success: - При безошибочном выполнении запроса тело ответа отсутствует - # response = await pachca.post_message_reactions( - # id=408643923, - # data=Postmessagereactions(code='👍') - # ) - - -delete_message_reactions: -errors: - errors=[Errors(key='reaction.id', value=None, message='Не удалось найти', code='not_found', payload=None)] - # response = await pachca.delete_message_reactions( - # id=408643923, - # code='' - # ) -success: - При безошибочном выполнении запроса тело ответа отсутствует - # response = await pachca.delete_message_reactions( - # id=408643923, - # code='👍' - # ) - - -get_message_reactions: -success: - data=[Data(user_id=515190, created_at='2025-01-08T15:18:10.000Z', code='👍')] - # response = await pachca.get_message_reactions( - # id=4086439232, - # ) -errors: - errors=[Errors(key='message.id', value='4086439232', message='Не удалось найти', code='not_found', payload=None)] - # response = await pachca.get_message_reactions( - # id=123, - # ) - - -create_task: -errors: - +АПИ позволяет сделать напоминание с due_at в прошлом - errors=[Errors(key='task.content', value='', message='Описание задачи обязательно для заполнения', code='blank', payload=None)] - # response = await pachca.create_task( - # data=Createtask( - # task={ - # 'kind': 'reminder', - # 'content': '', - # 'priority': 3, - # 'due_at': '2021-12-24T18:00:29.000Z' - # } - # ) - # ) -success: - data=Data(kind=, content='Сделать клиент и протестировать его.', due_at='2025-12-24T18:00:00.000Z', priority=, performer_ids=[515190], custom_properties=[], id=1068696, user_id=515190, status='undone', created_at='2025-01-08T15:26:03.000Z') - # response = await pachca.create_task( - # data=Createtask( - # task={ - # 'kind': 'reminder', - # 'content': 'Тестирование апи', - # 'priority': 3, - # 'due_at': '2025-12-24T18:00:29.000Z' - # } - # ) - # ) \ No newline at end of file From dbd7e200f885112dca612c5ec6bb78f0d8f29751 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 14:01:17 +0300 Subject: [PATCH 222/296] add generator2 and its packaging --- src/builder/Pipfile | 10 - src/builder/Pipfile.lock | 203 +-- src/builder/requirements_all.txt | 35 - src/builder/setup.py | 34 - src/openapi.yaml | 2359 ------------------------------ 5 files changed, 2 insertions(+), 2639 deletions(-) delete mode 100644 src/builder/requirements_all.txt delete mode 100644 src/builder/setup.py delete mode 100644 src/openapi.yaml diff --git a/src/builder/Pipfile b/src/builder/Pipfile index f079802..e984d06 100644 --- a/src/builder/Pipfile +++ b/src/builder/Pipfile @@ -5,7 +5,6 @@ name = "pypi" [packages] annotated-types = "==0.7.0" - anyio = "==4.7.0" attrs = "==24.3.0" black = "==24.10.0" @@ -36,7 +35,6 @@ platformdirs = "==4.3.6" prance = "==23.6.21.0" pre-commit = "==3.8.0" pydantic = "==2.10.4" -jinja2 = "==3.1.5" pydantic-core = "==2.27.2" python-dotenv = "==1.0.1" pyyaml = "==6.0.2" @@ -50,14 +48,6 @@ sniffio = "==1.3.1" tomli = "==2.2.1" typing-extensions = "==4.12.2" urllib3 = "==2.3.0" -markdown-it-py = "==3.0.0" -mdurl = "==0.1.2" -pygments = "==2.19.0" -python-dateutil = "==2.9.0.post0" -rich = "==13.9.4" -ruff = "==0.8.6" -shellingham = "==1.5.4" -typer = "==0.15.1" virtualenv = "==20.28.1" [dev-packages] diff --git a/src/builder/Pipfile.lock b/src/builder/Pipfile.lock index f709700..3517501 100644 --- a/src/builder/Pipfile.lock +++ b/src/builder/Pipfile.lock @@ -1,8 +1,7 @@ { "_meta": { "hash": { - "sha256": "744e7f7d38ac30aef12af9aaeb5d321d2b27751994f15b7dde921e6b6abee73f", - "sha256": "e0c39def9c9289d0f87a4fcd85226e903d2df379e5e2a32568808f15f3e5e262" + "sha256": "744e7f7d38ac30aef12af9aaeb5d321d2b27751994f15b7dde921e6b6abee73f" }, "pipfile-spec": 6, "requires": { @@ -29,14 +28,11 @@ "anyio": { "hashes": [ "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", - "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352", - "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", - "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a" + "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352" ], "index": "pypi", "markers": "python_version >= '3.9'", "version": "==4.7.0" - }, "attrs": { "hashes": [ @@ -76,7 +72,6 @@ "markers": "python_version >= '3.9'", "version": "==24.10.0" }, - "certifi": { "hashes": [ "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", @@ -86,7 +81,6 @@ "markers": "python_version >= '3.6'", "version": "==2024.12.14" }, - "cfgv": { "hashes": [ "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", @@ -204,7 +198,6 @@ "markers": "python_version >= '3.7'", "version": "==3.4.1" }, - "click": { "hashes": [ "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", @@ -231,7 +224,6 @@ "index": "pypi", "version": "==0.3.9" }, - "exceptiongroup": { "hashes": [ "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", @@ -241,15 +233,12 @@ "markers": "python_version >= '3.7'", "version": "==1.2.2" }, - "filelock": { "hashes": [ "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435" ], - "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==3.16.1" }, @@ -280,7 +269,6 @@ "markers": "python_version >= '3.8'", "version": "==0.28.1" }, - "identify": { "hashes": [ "sha256:285a7d27e397652e8cafe537a6cc97dd470a970f48fb2e9d979aa38eae5513ac", @@ -290,7 +278,6 @@ "markers": "python_version >= '3.9'", "version": "==2.6.4" }, - "idna": { "hashes": [ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", @@ -300,7 +287,6 @@ "markers": "python_version >= '3.6'", "version": "==3.10" }, - "jsonschema": { "hashes": [ "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", @@ -389,102 +375,6 @@ "index": "pypi", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", "version": "==1.9.1" - - "jinja2": { - "hashes": [ - "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", - "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.1.5" - }, - "markdown-it-py": { - "hashes": [ - "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", - "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==3.0.0" - }, - "markupsafe": { - "hashes": [ - "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", - "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", - "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", - "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", - "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", - "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", - "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", - "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", - "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", - "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", - "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", - "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", - "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", - "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", - "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", - "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", - "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", - "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", - "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", - "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", - "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", - "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", - "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", - "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", - "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", - "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", - "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", - "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", - "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", - "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", - "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", - "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", - "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", - "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", - "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", - "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", - "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", - "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", - "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", - "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", - "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", - "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", - "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", - "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", - "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", - "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", - "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", - "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", - "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", - "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", - "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", - "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", - "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", - "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", - "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", - "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", - "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", - "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", - "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", - "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", - "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==3.0.2" - }, - "mdurl": { - "hashes": [ - "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", - "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==0.1.2" - }, "packaging": { "hashes": [ @@ -495,7 +385,6 @@ "markers": "python_version >= '3.8'", "version": "==24.2" }, - "pathable": { "hashes": [ "sha256:5c869d315be50776cc8a993f3af43e0c60dc01506b399643f919034ebf4cdcab", @@ -514,7 +403,6 @@ "markers": "python_version >= '3.8'", "version": "==0.12.1" }, - "platformdirs": { "hashes": [ "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", @@ -524,7 +412,6 @@ "markers": "python_version >= '3.8'", "version": "==4.3.6" }, - "prance": { "hashes": [ "sha256:6a4276fa07ed9f22feda4331097d7503c4adc3097e46ffae97425f2c1026bd9f", @@ -543,7 +430,6 @@ "markers": "python_version >= '3.9'", "version": "==3.8.0" }, - "pydantic": { "hashes": [ "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", @@ -660,7 +546,6 @@ "markers": "python_version >= '3.8'", "version": "==2.27.2" }, - "python-dotenv": { "hashes": [ "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", @@ -951,77 +836,6 @@ "index": "pypi", "markers": "python_version >= '3.7'", "version": "==0.7.1" - - "pygments": { - "hashes": [ - "sha256:4755e6e64d22161d5b61432c0600c923c5927214e7c956e31c23923c89251a9b", - "sha256:afc4146269910d4bdfabcd27c24923137a74d562a23a320a41a55ad303e19783" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.19.0" - }, - "python-dateutil": { - "hashes": [ - "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", - "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==2.9.0.post0" - }, - "python-dotenv": { - "hashes": [ - "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", - "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.0.1" - }, - "rich": { - "hashes": [ - "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", - "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==13.9.4" - }, - "ruff": { - "hashes": [ - "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", - "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", - "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", - "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", - "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", - "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", - "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1", - "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", - "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", - "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162", - "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", - "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", - "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", - "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", - "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", - "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764", - "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807", - "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==0.8.6" - }, - "shellingham": { - "hashes": [ - "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", - "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.5.4" - }, "six": { "hashes": [ @@ -1041,7 +855,6 @@ "markers": "python_version >= '3.7'", "version": "==1.3.1" }, - "tomli": { "hashes": [ "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", @@ -1080,16 +893,6 @@ "index": "pypi", "markers": "python_version >= '3.8'", "version": "==2.2.1" - - "typer": { - "hashes": [ - "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", - "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==0.15.1" - }, "typing-extensions": { "hashes": [ @@ -1100,7 +903,6 @@ "markers": "python_version >= '3.8'", "version": "==4.12.2" }, - "urllib3": { "hashes": [ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", @@ -1110,7 +912,6 @@ "markers": "python_version >= '3.9'", "version": "==2.3.0" }, - "virtualenv": { "hashes": [ "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb", diff --git a/src/builder/requirements_all.txt b/src/builder/requirements_all.txt deleted file mode 100644 index 72ef60d..0000000 --- a/src/builder/requirements_all.txt +++ /dev/null @@ -1,35 +0,0 @@ -annotated-types==0.7.0 -anyio==4.8.0 -attrs==24.3.0 -certifi==2024.12.14 -click==8.1.8 -colorama==0.4.6 -distlib==0.3.9 -filelock==3.16.1 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.28.1 -idna==3.10 -Jinja2==3.1.5 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mdurl==0.1.2 -openapi-python-client==0.23.0 -packaging==24.2 -pipenv==2024.4.0 -platformdirs==4.3.6 -pydantic==2.10.4 -pydantic_core==2.27.2 -Pygments==2.19.0 -python-dateutil==2.9.0.post0 -python-dotenv==1.0.1 -rich==13.9.4 -ruamel.yaml==0.18.9 -ruamel.yaml.clib==0.2.12 -ruff==0.8.6 -shellingham==1.5.4 -six==1.17.0 -sniffio==1.3.1 -typer==0.15.1 -typing_extensions==4.12.2 -virtualenv==20.28.1 diff --git a/src/builder/setup.py b/src/builder/setup.py deleted file mode 100644 index 6cb24f4..0000000 --- a/src/builder/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -from setuptools import setup, find_packages - -import json -import os -from pathlib import Path - -this_directory = Path(__file__).parent -long_description = (this_directory / "../../README.md").read_text() - - -def read_pipenv_dependencies(fname): - """Получаем из Pipfile.lock зависимости по умолчанию.""" - filepath = os.path.join(os.path.dirname(__file__), fname) - with open(filepath) as lockfile: - lockjson = json.load(lockfile) - return [dependency for dependency in lockjson.get('default')] - - -if __name__ == '__main__': - setup( - name='pachca', - long_description=long_description, - long_description_content_type='text/markdown', - version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), - package_dir={'': '../generator1/pachca-api-open-api-3-0-client'}, - packages=find_packages( - '../generator1/pachca-api-open-api-3-0-client', include=[ - 'pachca_api_open_api_3_0_client*'] - ), - description='A pachca_api package.', - install_requires=[ - *read_pipenv_dependencies('Pipfile.lock'), - ] - ) diff --git a/src/openapi.yaml b/src/openapi.yaml deleted file mode 100644 index 4527bb9..0000000 --- a/src/openapi.yaml +++ /dev/null @@ -1,2359 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - enum: - - User - - Task - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - - $ref: '#/components/parameters/queryParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/Status' - responses: - '201': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - $ref: '#/components/parameters/sortParameter' - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - - $ref: '#/components/parameters/availabilityParameter' - - $ref: '#/components/parameters/last_message_at_afterParameter' - - $ref: '#/components/parameters/last_message_at_beforeParameter' - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '201': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '201': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '200': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '200': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - $ref: '#/components/parameters/chatParameter' - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - $ref: '#/components/parameters/reactionParameter' - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - $ref: '#/components/schemas/BaseTask' - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - parameters: - perParameter50: - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - perParameter25: - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - pageParameter: - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - queryParameter: - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - chatParameter: - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - sortParameter: - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - availabilityParameter: - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - last_message_at_afterParameter: - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - last_message_at_beforeParameter: - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - reactionParameter: - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: array - items: - title: Error - type: object - properties: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - properties: - id: - type: integer - description: Идентификатор поля - chat_id: - type: integer - description: Идентификатор поля чата - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: object - required: - - key - - name - - file_type - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - enum: - - file - - image - CreateEditFiles: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Create&Edit Files - required: - - size - properties: - size: - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Files - properties: - id: - type: integer - description: Идентификатор поля - url: - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - discussion - - user - - thread - default: discussion - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - allOf: - - $ref: '#/components/schemas/Files' - title: files - thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - description: Задаваемые дополнительные поля - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: object - title: Custom Properties - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] From cdefa8c18650ca9aec9bbfc5284abf0841a19412 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 14:09:59 +0300 Subject: [PATCH 223/296] fixed generator1 --- src/generator1/openapi.yaml | 1823 ++++++++------- src/generator1/openapi_new.yaml | 2365 -------------------- src/generator1/openapi_schemas_errors.yaml | 2047 ----------------- 3 files changed, 982 insertions(+), 5253 deletions(-) delete mode 100644 src/generator1/openapi_new.yaml delete mode 100644 src/generator1/openapi_schemas_errors.yaml diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml index 2ba3ca1..0f96d4a 100644 --- a/src/generator1/openapi.yaml +++ b/src/generator1/openapi.yaml @@ -41,14 +41,14 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type in: query - description: Тип сущности - участник (User) или напоминание (Task). + description: Тип сущности required: true schema: type: string @@ -63,30 +63,41 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Поле не может быть пустым value: - detail: BLANK - INCLUSION: - summary: inclusion + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: description: Поле имеет непредусмотренное значение value: - detail: INCLUSION + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /uploads: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -99,30 +110,34 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: - '204': - description: Успешный запрос. + '201': + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: - employees summary: получение актуального списка всех сотрудников компании description: | - Fetch a paginated list of employees with optional filtering by query. + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - name: per in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) required: false schema: type: integer @@ -138,8 +153,7 @@ paths: - name: query in: query description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) required: false schema: type: string @@ -181,19 +195,29 @@ paths: properties: data: $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /profile/status: get: tags: - status summary: получение информации о своем статусе description: | - Параметры запроса отсутствуют + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. operationId: getStatus responses: '200': @@ -210,16 +234,19 @@ paths: - status summary: новый статус description: | - Создание нового статуса. + Метод для установки себе нового статуса. operationId: putStatus requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/QueryStatus' + type: object + properties: + status: + $ref: '#/components/schemas/QueryStatus' responses: - '201': + '200': description: Объект создан content: application/json: @@ -229,50 +256,68 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Обязательное поле (не может быть пустым) value: - detail: BLANK - TOO_LONG: - summary: too_long + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: description: Слишком длинное значение (пояснения вы получите в поле message) value: - detail: TOO_LONG - INVALID: - summary: invalid + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) value: - detail: INVALID - WRONG_EMOJI: - summary: wrong_emoji + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: description: Emoji статуса не может содержать значения отличные от Emoji символа value: - detail: WRONG_EMOJI + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} delete: tags: - status summary: удаление своего статуса description: | - Параметры запроса отсутствуют + Метод для удаления своего статуса. Параметры запроса отсутствуют. operationId: delStatus responses: '204': - description: Объект успешно удален, тело ответа отсутствует + description: При безошибочном выполнении запроса тело ответа отсутствует content: {} /group_tags/{id}: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -291,45 +336,31 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - name: per @@ -342,7 +373,7 @@ paths: maximum: 50 - name: page in: query - description: Страница выборки (по умолчанию 1) + description: Страница выборки (по умолчанию 1) required: false schema: type: integer @@ -359,43 +390,22 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: exclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -404,6 +414,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -413,7 +425,7 @@ paths: type: integer - name: per in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) required: false schema: type: integer @@ -439,20 +451,30 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} /chats: post: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -461,7 +483,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -473,14 +495,11 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: blank: description: Обязательное поле (не может быть пустым) @@ -509,16 +528,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -533,10 +542,7 @@ paths: content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: invalid: description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) @@ -551,8 +557,11 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - name: 'sort[id]' in: query @@ -569,16 +578,16 @@ paths: default: desc - name: per in: query - required: false description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false schema: type: integer default: 25 maximum: 50 - name: page in: query - required: false description: Страница выборки (по умолчанию 1) + required: false schema: type: integer default: 1 @@ -626,14 +635,11 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -653,16 +659,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -677,10 +673,7 @@ paths: content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: invalid: description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) @@ -696,7 +689,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -717,15 +710,12 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: not_found: description: Не удалось найти @@ -754,32 +744,75 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены - '404': - description: 'Не удалось найти' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -798,76 +831,128 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/leave: delete: tags: - talk and channel participants operationId: leaveChat - summary: 'Выход из беседы или канала' + summary: выход из беседы или канала description: |- - Метод для самостоятельного выхода из беседы или канала. + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ parameters: - name: id in: path required: true - description: 'Уникальный идентификатор беседы или канала.' + description: Уникальный идентификатор беседы или канала. schema: type: integer responses: '200': - description: 'Успешно отписан. Тело ответа отсутствует' + description: При безошибочном выполнении запроса тело ответа отсутствуе '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Errors' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /messages/{id}/thread: - post: - tags: - - comments - summary: Создание нового треда - description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: + - comments + summary: создание нового треда + description: | + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id in: path required: true description: Уникальный идентификатор сообщения, к которому создается тред. @@ -882,37 +967,41 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -942,11 +1031,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -971,41 +1055,40 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - messages @@ -1017,6 +1100,7 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - name: chat_id @@ -1028,19 +1112,17 @@ paths: type: integer - name: per in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false schema: - title: per type: integer default: 25 maximum: 50 - name: page in: query description: Страница выборки (по умолчанию 1) + required: false schema: - title: page type: integer default: 1 responses: @@ -1095,41 +1177,40 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1184,23 +1265,27 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1227,32 +1312,47 @@ paths: type: object properties: data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' + $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1271,84 +1371,76 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: - "204": + "201": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - error: - type: string - description: Описание ошибки. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} delete: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1361,122 +1453,78 @@ paths: type: integer - name: code in: query - required: true - description: Emoji, который нужно удалить. + description: Emoji в строковом формате для добавления реакции. schema: type: string + example: "👍" responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" - get: - tags: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path + description: Уникальный идентификатор сообщения required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 responses: '200': description: Список реакций успешно получен. @@ -1489,25 +1537,40 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /tasks: post: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1564,70 +1627,95 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - error: - type: string - description: Описание ошибки - + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1654,6 +1742,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1662,6 +1754,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1683,6 +1778,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1692,48 +1792,6 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - FileResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - direct_url: - type: string - DirectResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1757,6 +1815,55 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. + BaseResponse: + title: Base Response + type: object + properties: + Content-Disposition: + type: string + description: Используемый заголовок + default: attachment + acl: + type: string + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла Status: type: object nullable: true @@ -1795,7 +1902,8 @@ components: format: date-time description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ nullable: true - QueryCommonMethods: + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1809,38 +1917,39 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден + description: тип поля + Errors: type: object properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string - Errors: - title: Errors - type: array - items: - title: Error - type: object - properties: - key: - title: key - type: string - value: - title: value - type: string - message: - title: message - type: string - code: - title: code - type: string - payload: - title: payload - type: object + errors: + type: array + items: + key: + title: key + type: string + description: Ключ параметра, в котором произошла ошибка + value: + title: value + type: string + description: Значение ключа, которое вызвало ошибку + message: + title: message + type: string + description: Ошибка текстом, который вы можете вывести пользователю + code: + title: code + type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) + payload: + title: payload + type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) Buttons: title: Message Buttons type: array @@ -1867,111 +1976,149 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Base Thread + type: object + properties: + id: + type: integer + description: Идентификатор поля + chat_id: + type: integer + description: Идентификатор поля чата + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files type: object required: - - entity_id - - content + - key + - name + - file_type properties: - entity_type: - title: Entity Type + key: type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: type: string - files: + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + Files: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object title: Files - type: array - items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - size: - title: Size - type: integer - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - EditMessages: + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения - files: - type: object + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - discussion + - user + - thread + default: discussion + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: type: object properties: @@ -2029,64 +2176,6 @@ components: title: Url type: string description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. Reaction: type: object properties: @@ -2103,81 +2192,8 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2195,6 +2211,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2203,6 +2225,33 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. @@ -2216,6 +2265,98 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http diff --git a/src/generator1/openapi_new.yaml b/src/generator1/openapi_new.yaml deleted file mode 100644 index 0f96d4a..0000000 --- a/src/generator1/openapi_new.yaml +++ /dev/null @@ -1,2365 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '201': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/QueryStatus' - responses: - '200': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '201': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '201': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '200': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '201': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "201": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: object - properties: - errors: - type: array - items: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - properties: - id: - type: integer - description: Идентификатор поля - chat_id: - type: integer - description: Идентификатор поля чата - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: object - required: - - key - - name - - file_type - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - enum: - - file - - image - CreateEditFiles: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Create&Edit Files - required: - - size - properties: - size: - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Files - properties: - id: - type: integer - description: Идентификатор поля - url: - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - discussion - - user - - thread - default: discussion - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - description: Задаваемые дополнительные поля - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: object - title: Custom Properties - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] \ No newline at end of file diff --git a/src/generator1/openapi_schemas_errors.yaml b/src/generator1/openapi_schemas_errors.yaml deleted file mode 100644 index 41a48f7..0000000 --- a/src/generator1/openapi_schemas_errors.yaml +++ /dev/null @@ -1,2047 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: Список дополнительных полей - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - участник (User) или напоминание (Task). - required: true - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/QueryCommonMethods' - '400': - description: BadRequest - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /uploads: - post: - tags: - - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '204': - description: Успешный запрос. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Fetch a paginated list of employees with optional filtering by query. - operationId: getEmployees - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Параметры запроса отсутствуют - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Создание нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/QueryStatus' - responses: - '201': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: BadRequest - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - delete: - tags: - - status - summary: удаление своего статуса - description: | - Параметры запроса отсутствуют - operationId: delStatus - responses: - '204': - description: Объект успешно удален, тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: Информация о теге - description: | - Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - summary: Тег не найден. - value: - errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" - /group_tags: - get: - tags: - - tags - summary: Список тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - operationId: getTags - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос - value: - errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Поле имеет недопустимое значение - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: Новая беседа или канал - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/QueryChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. - parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - required: false - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - required: false - description: Страница выборки (по умолчанию 1) - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: Информация о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: Массив идентификаторов пользователей, которые станут участниками - content: - application/json: - schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - responses: - '201': - description: Пользователи добавлены - '400': - description: BadRequest - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - responses: - '201': - description: Тег(и) добавлен(ы) - '400': - description: BadRequest - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: 'Выход из беседы или канала' - description: |- - Метод для самостоятельного выхода из беседы или канала. - parameters: - - name: id - in: path - required: true - description: 'Уникальный идентификатор беседы или канала.' - schema: - type: integer - responses: - '200': - description: 'Успешно отписан. Тело ответа отсутствует' - '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - '404': - description: 'Не удалось найти' - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /messages/{id}/thread: - post: - tags: - - comments - summary: Создание нового треда - description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '201': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - '400': - description: Неверный запрос. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - REQUIRED FIELD BLANK: - summary: required fields blank - value: - errors: - - key: content - value: null - message: Поле не может быть пустым - code: blank - INVALID FIELD VALUE: - summary: invalid field value - value: - errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение - code: exclusion - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - operationId: getListMessage - parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) - schema: - title: per - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - schema: - title: page - type: integer - default: 1 - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - REQUIRED FIELD BLANK: - summary: required fields blank - value: - errors: - - key: chat_id - value: null - message: Поле не может быть пустым - code: blank - INVALID FIELD VALUE: - summary: invalid field value - value: - errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение - code: exclusion - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found - put: - tags: - - message - operationId: editMessage - summary: Редактирование сообщения - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - '400': - description: Нельзя покинуть персональный чат - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - '404': - description: 'Не удалось найти' - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: Добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code - responses: - "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank_field: - summary: Поле code пустое - value: - error: blank - exclusion: - summary: Недопустимое значение эмодзи - value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - summary: Сообщение не существует - value: - error: not_found - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: Удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - name: code - in: query - required: true - description: Emoji, который нужно удалить. - schema: - type: string - responses: - "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank_field: - summary: Поле code пустое - value: - errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" - exclusion: - summary: Недопустимое значение эмодзи - value: - errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - summary: Сообщение или реакция не найдены - value: - errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" - get: - tags: - - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. - operationId: getMessageReactions - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. - schema: - type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - '400': - description: Неверный запрос. - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: 'Метод для создания нового напоминания.' - description: | - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - - '400': - description: Ошибка запроса - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - -components: - schemas: - BaseEmployee: - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - FileResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - direct_url: - type: string - DirectResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - QueryCommonMethods: - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - example: number - description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден - type: object - properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string - Errors: - type: object - properties: - errors: - type: array - items: - key: - title: key - type: string - value: - title: value - type: string - message: - title: message - type: string - code: - title: code - type: string - payload: - title: payload - type: object - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - CreateMessage: - type: object - required: - - entity_id - - content - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - files: - title: Files - type: array - items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - size: - title: Size - type: integer - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - EditMessages: - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - files: - type: object - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - enum: - - 'file' - - 'image' - size: - type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки - Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] From 6790c919c8f826240f5fd022427f7c1ff0f630a2 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 14:14:40 +0300 Subject: [PATCH 224/296] fixed new_yaml --- src/generator1/openapi.yaml | 1825 ++++++++++++----------- src/generator1/openapi_new.yaml | 2396 ------------------------------- 2 files changed, 982 insertions(+), 3239 deletions(-) delete mode 100644 src/generator1/openapi_new.yaml diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml index dec1f58..0f96d4a 100644 --- a/src/generator1/openapi.yaml +++ b/src/generator1/openapi.yaml @@ -41,14 +41,14 @@ paths: get: tags: - common methods - summary: Список дополнительных полей + summary: получение списка актульных полей сущности description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) operationId: getCommonMethods parameters: - name: entity_type in: query - description: Тип сущности - участник (User) или напоминание (Task). + description: Тип сущности required: true schema: type: string @@ -63,30 +63,41 @@ paths: data: type: array items: - $ref: '#/components/schemas/QueryCommonMethods' + $ref: '#/components/schemas/CommonMethods' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Поле не может быть пустым value: - detail: BLANK - INCLUSION: - summary: inclusion + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: description: Поле имеет непредусмотренное значение value: - detail: INCLUSION + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} /uploads: post: tags: - common methods - summary: Получение подписи и ключа для загрузки файла - description: Возвращает параметры, необходимые для безопасной загрузки файла. + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. operationId: getUploads responses: '200': @@ -99,30 +110,34 @@ paths: post: tags: - common methods - summary: Получение URL для загрузки - description: Отправляет запрос для получения URL для безопасной загрузки файла. + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. operationId: getDirectUrl requestBody: required: true content: multipart/form-data: schema: - $ref: '#/components/schemas/DirectResponse' + $ref: '#/components/schemas/DirectResponse' responses: - '204': - description: Успешный запрос. + '201': + description: При безошибочном выполнении запроса тело ответа отсутствует. /users: get: tags: - employees summary: получение актуального списка всех сотрудников компании description: | - Fetch a paginated list of employees with optional filtering by query. + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) operationId: getEmployees parameters: - name: per in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) required: false schema: type: integer @@ -138,8 +153,7 @@ paths: - name: query in: query description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), - email (электронная почта), phone_number (телефон) и nickname (никнейм)) + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) required: false schema: type: string @@ -181,19 +195,29 @@ paths: properties: data: $ref: '#/components/schemas/Employee' - '404': - description: Сотрудник не найден + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /profile/status: get: tags: - status summary: получение информации о своем статусе description: | - Параметры запроса отсутствуют + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. operationId: getStatus responses: '200': @@ -210,16 +234,19 @@ paths: - status summary: новый статус description: | - Создание нового статуса. + Метод для установки себе нового статуса. operationId: putStatus requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/QueryStatus' + type: object + properties: + status: + $ref: '#/components/schemas/QueryStatus' responses: - '201': + '200': description: Объект создан content: application/json: @@ -229,50 +256,68 @@ paths: data: $ref: '#/components/schemas/Status' '400': - description: BadRequest + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - BLANK: - summary: blank + blank: description: Обязательное поле (не может быть пустым) value: - detail: BLANK - TOO_LONG: - summary: too_long + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: description: Слишком длинное значение (пояснения вы получите в поле message) value: - detail: TOO_LONG - INVALID: - summary: invalid + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: description: Поле не соответствует правилам (пояснения вы получите в поле message) value: - detail: INVALID - WRONG_EMOJI: - summary: wrong_emoji + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: description: Emoji статуса не может содержать значения отличные от Emoji символа value: - detail: WRONG_EMOJI + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} delete: tags: - status summary: удаление своего статуса description: | - Параметры запроса отсутствуют + Метод для удаления своего статуса. Параметры запроса отсутствуют. operationId: delStatus responses: '204': - description: Объект успешно удален, тело ответа отсутствует + description: При безошибочном выполнении запроса тело ответа отсутствует content: {} /group_tags/{id}: get: tags: - tags - summary: Информация о теге + summary: получение информации о теге description: | - Параметры запроса отсутствуют + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют operationId: getTag parameters: - name: id @@ -291,45 +336,31 @@ paths: properties: data: $ref: '#/components/schemas/Tag' - "404": - description: Тег не найден. + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object + $ref: '#/components/schemas/Errors' examples: not_found: - summary: Тег не найден. + description: Не удалось найти value: errors: - - key: "id" - value: "100500" - message: "Не удалось найти тег" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} /group_tags: get: tags: - tags - summary: Список тегов сотрудников + summary: получение актуального списка тегов сотрудников description: | Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) operationId: getTags parameters: - name: per @@ -342,7 +373,7 @@ paths: maximum: 50 - name: page in: query - description: Страница выборки (по умолчанию 1) + description: Страница выборки (по умолчанию 1) required: false schema: type: integer @@ -359,43 +390,22 @@ paths: type: array items: $ref: '#/components/schemas/Tag' - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: exclusion: - summary: Недопустимое значение количество возвращаемых сущностей за один запрос + description: Поле имеет непредусмотренное значение value: errors: - - key: "per" - value: "51" - message: "Поле имеет недопустимое значение" - code: "exclusion" + - key: string + value: string + message: message + code: exclusion + payload: {} /group_tags/{id}/users: get: tags: @@ -404,6 +414,8 @@ paths: summary: получение актуального списка сотрудников тега description: | Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) parameters: - name: id in: path @@ -413,7 +425,7 @@ paths: type: integer - name: per in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) required: false schema: type: integer @@ -439,20 +451,30 @@ paths: items: $ref: '#/components/schemas/BaseEmployee' '400': - description: Поле имеет недопустимое значение + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} /chats: post: tags: - chats and channels operationId: createChat - summary: Новая беседа или канал + summary: создание новой беседы или канала description: | Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником.\ + При создании беседы или канала вы автоматически становитесь участником. requestBody: required: true content: @@ -461,7 +483,7 @@ paths: type: object properties: chat: - $ref: '#/components/schemas/QueryChat' + $ref: '#/components/schemas/BaseChat' responses: '201': description: Запрос отработал успешно, сущность создана @@ -473,14 +495,11 @@ paths: data: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: blank: description: Обязательное поле (не может быть пустым) @@ -509,16 +528,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -533,10 +542,7 @@ paths: content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: invalid: description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) @@ -551,8 +557,11 @@ paths: tags: - chats and channels operationId: getChats - summary: Список бесед и каналов - description: Получения списка бесед и каналов по заданным параметрам. + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) parameters: - name: 'sort[id]' in: query @@ -569,16 +578,16 @@ paths: default: desc - name: per in: query - required: false description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false schema: type: integer default: 25 maximum: 50 - name: page in: query - required: false description: Страница выборки (по умолчанию 1) + required: false schema: type: integer default: 1 @@ -626,14 +635,11 @@ paths: items: $ref: '#/components/schemas/Chat' '400': - description: Неприемлемый запрос (часто из-за отсутствия обязательного параметра) + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' examples: too_long: description: Слишком длинное значение (пояснения вы получите в поле message) @@ -653,16 +659,6 @@ paths: message: message code: invalid payload: {} - '404': - description: Запрашиваемый ресурс не существует - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: not_found: description: Не удалось найти value: @@ -677,10 +673,7 @@ paths: content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: invalid: description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) @@ -696,7 +689,7 @@ paths: tags: - chats and channels operationId: getChat - summary: Информация о беседе или канале + summary: получение информации о беседе или канале description: | Получения информации о беседе или канале. Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. @@ -717,15 +710,12 @@ paths: properties: data: $ref: '#/components/schemas/Chat' - '404': - description: Запрашиваемый ресурс не существует + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' + $ref: '#/components/schemas/Errors' examples: not_found: description: Не удалось найти @@ -754,34 +744,75 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов пользователей, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - member_ids - type: object - properties: - member_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean + $ref: '#/components/schemas/MembersChat' responses: '201': description: Пользователи добавлены '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/group_tags: post: tags: @@ -800,83 +831,135 @@ paths: format: int64 example: 533 requestBody: - description: Массив идентификаторов тегов, которые станут участниками + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса content: application/json: schema: - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] + $ref: '#/components/schemas/GroupTag' responses: '201': description: Тег(и) добавлен(ы) '400': - description: BadRequest + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} /chats/{id}/leave: delete: tags: - talk and channel participants operationId: leaveChat - summary: 'Выход из беседы или канала' + summary: выход из беседы или канала description: |- - Метод для самостоятельного выхода из беседы или канала. + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ parameters: - name: id in: path required: true - description: 'Уникальный идентификатор беседы или канала.' + description: Уникальный идентификатор беседы или канала. schema: type: integer responses: '200': - description: 'Успешно отписан. Тело ответа отсутствует' + description: При безошибочном выполнении запроса тело ответа отсутствуе '400': - description: 'Нельзя покинуть персональный чат' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - /messages/{id}/thread: - post: - tags: - - comments - summary: Создание нового треда - description: | - Этот метод позволяет создать новый тред к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: + - comments + summary: создание нового треда + description: | + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id in: path required: true description: Уникальный идентификатор сообщения, к которому создается тред. schema: type: integer responses: - '200': + '201': description: Тред успешно создан или возвращены данные существующего треда. content: application/json: @@ -884,37 +967,41 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного треда. - chat_id: - type: integer - description: Идентификатор чата треда. - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' + $ref: '#/components/schemas/Thread' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages: post: tags: @@ -944,11 +1031,6 @@ paths: properties: message: $ref: '#/components/schemas/CreateMessage' - example: - message: - entity_type: discussion - entity_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) responses: '201': description: Successful @@ -973,41 +1055,40 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - example: - errors: - - key: entyti_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: content - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: entity_type - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - messages @@ -1019,6 +1100,7 @@ paths: треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) operationId: getListMessage parameters: - name: chat_id @@ -1030,19 +1112,17 @@ paths: type: integer - name: per in: query - description: | - Количество возвращаемых сущностей за один запрос - (по умолчанию 25, максимум 50) + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false schema: - title: per type: integer default: 25 maximum: 50 - name: page in: query description: Страница выборки (по умолчанию 1) + required: false schema: - title: page type: integer default: 1 responses: @@ -1097,41 +1177,40 @@ paths: thread: null forwarding: null parent_message_id: null - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: chat_id - value: 1 - message: Не удалось найти - code: not_found '400': - description: Bad Request + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' examples: - REQUIRED FIELD BLANK: - summary: required fields blank + blank: + description: Поле не может быть пустым value: errors: - - key: chat_id - value: null - message: Поле не может быть пустым + - key: name + value: '' + message: message code: blank - INVALID FIELD VALUE: - summary: invalid field value + payload: {} + exclusion: + description: Поле имеет недопустимое значение value: errors: - - key: chat_id - value: chat - message: Поле имеет недопустимое значение + - key: name + value: 1234 + message: message code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}: get: tags: @@ -1186,23 +1265,27 @@ paths: chat_id: 1949863 forwarding: null parent_message_id: 194274 - '404': - description: Not Found + '400': + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/NotFound' - example: - errors: - - key: id - value: 0 - message: Не удалось найти - code: not_found + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} put: tags: - - message + - messages operationId: editMessage - summary: Редактирование сообщения + summary: редактирование сообщения по указанному идентификатору description: Метод для редактирования сообщения или комментария. parameters: - name: id @@ -1229,32 +1312,47 @@ paths: type: object properties: data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' + $ref: '#/components/schemas/Message' '400': - description: Нельзя покинуть персональный чат - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' - '404': - description: 'Не удалось найти' + description: Пояснения ошибки content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ErrorsCode' + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /messages/{id}/reactions: post: tags: - reactions to messages operationId: postMessageReactions - summary: Добавление реакции + summary: добавление реакции description: > Метод для добавления реакции на сообщение. **Лимиты реакций:** @@ -1273,84 +1371,76 @@ paths: content: application/json: schema: - type: object - properties: - code: - type: string - description: Emoji в строковом формате для добавления реакции. - required: - - code + $ref: '#/components/schemas/CodeReaction' responses: - "204": + "201": description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - error: - type: string - description: Описание ошибки. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: - error: blank + errors: + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: - error: exclusion - - "403": - description: Превышение лимитов по реакциям. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Описание ошибки. - examples: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} user_limit: - summary: Превышен лимит уникальных реакций пользователя + description: Превышен лимит уникальных реакций пользователя value: - error: user_limit - message: "Вы можете добавить не более 20 уникальных реакций." + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} unique_limit: - summary: Превышен лимит уникальных реакций на сообщение + description: Превышен лимит уникальных реакций на сообщение value: - error: unique_limit - message: "Сообщение может содержать не более 30 уникальных реакций." + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} general_limit: - summary: Превышен общий лимит реакций на сообщение - value: - error: general_limit - message: "Сообщение может содержать не более 1000 реакций." - - "404": - description: Сообщение не найдено. - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Сообщение не найдено. - examples: - not_found: - summary: Сообщение не существует + description: Превышен общий лимит реакций на сообщение value: - error: not_found + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} delete: tags: - reactions to messages operationId: deleteMessageReactions - summary: Удаление реакции + summary: удаление реакции description: > Метод для удаления реакции на сообщение. Удалить можно только те реакции, которые были поставлены авторизованным пользователем. @@ -1363,122 +1453,78 @@ paths: type: integer - name: code in: query - required: true - description: Emoji, который нужно удалить. + description: Emoji в строковом формате для добавления реакции. schema: type: string + example: "👍" responses: "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - - "400": - description: Ошибка валидации запроса. + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - errors: - type: array - description: Список ошибок в запросе. - items: - type: object - properties: - key: - type: string - description: Ключ параметра, в котором произошла ошибка. - value: - type: string - description: Значение ключа, вызвавшее ошибку. - message: - type: string - description: Текстовое описание ошибки. - code: - type: string - description: Внутренний код ошибки. - payload: - type: object - description: Дополнительная информация об ошибке. + $ref: '#/components/schemas/Errors' examples: - blank_field: - summary: Поле code пустое + blank: + description: Поле не может быть пустым value: errors: - - key: "code" - value: "" - message: "Поле не может быть пустым" - code: "blank" + - key: name + value: '' + message: message + code: blank + payload: {} exclusion: - summary: Недопустимое значение эмодзи + description: Поле имеет недопустимое значение value: errors: - - key: "code" - value: "invalid_emoji" - message: "Поле имеет недопустимое значение" - code: "exclusion" - - "404": - description: Сообщение или реакция не найдены. - content: - application/json: - schema: - type: object - properties: - errors: - type: array - description: Список ошибок. - items: - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - examples: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} not_found: - summary: Сообщение или реакция не найдены + description: Не удалось найти value: errors: - - key: "reaction" - value: "😊" - message: "Не удалось найти реакцию" - code: "not_found" + - key: string + value: string + message: message + code: not_found + payload: {} get: tags: - reactions to messages - summary: 'Получение актуального списка реакций.' - description: | - Этот метод позволяет получить список всех реакций, оставленных пользователями на указанное сообщение. operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса parameters: - name: id in: path + description: Уникальный идентификатор сообщения required: true - description: Уникальный идентификатор сообщения, список реакций на которое нужно получить. schema: type: integer - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - per: - type: integer - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50). - default: 50 - maximum: 50 - page: - type: integer - description: Номер страницы выборки (по умолчанию 1). - default: 1 + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 responses: '200': description: Список реакций успешно получен. @@ -1491,25 +1537,40 @@ paths: type: array items: $ref: '#/components/schemas/Reaction' - '404': - description: Сообщение не найдено. - content: - application/json: - schema: - $ref: '#/components/schemas/NotFound' '400': - description: Неверный запрос. + description: Пояснения ошибки content: application/json: schema: - $ref: '#/components/schemas/BadRequest' + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} /tasks: post: tags: - reminders operationId: createTask - summary: 'Метод для создания нового напоминания.' + summary: создание нового напоминания description: | + Метод для создания нового напоминания. + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. @@ -1566,70 +1627,95 @@ paths: type: object properties: data: - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - kind: - type: string - description: Тип - content: - type: string - description: Описание - due_at: - type: string - format: date-time - description: Срок выполнения (ISO-8601) - priority: - type: integer - description: Приоритет - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - performer_ids: - type: array - items: - type: integer - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - + $ref: '#/components/schemas/Task' '400': - description: Ошибка запроса + description: Пояснения ошибки content: application/json: schema: - type: object - properties: - error: - type: string - description: Описание ошибки - + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} components: schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code BaseEmployee: + title: Base Employee type: object properties: id: @@ -1656,6 +1742,10 @@ components: description: Департамент role: type: string + enum: + - admin + - user + - multi_guest description: | Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) suspended: @@ -1664,6 +1754,9 @@ components: Деактивация пользователя. При значении true пользователь является деактивированным. invite_status: type: string + enum: + - confirmed + - sent description: | Статус приглашения: confirmed (принято), sent (отправлено) list_tags: @@ -1685,6 +1778,11 @@ components: description: Название поля data_type: type: string + enum: + - string + - number + - date + - link description: Тип поля (string, number, date или link) value: type: string @@ -1694,48 +1792,6 @@ components: description: | Тип: пользователь (false) или бот (true) description: Базовый класс сотрудника. - FileResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - direct_url: - type: string - DirectResponse: - type: object - properties: - Content-Disposition: - type: string - acl: - type: string - policy: - type: string - x-amz-credential: - type: string - x-amz-algorithm: - type: string - x-amz-date: - type: string - x-amz-signature: - type: string - key: - type: string - file: - type: string Employee: allOf: - $ref: '#/components/schemas/BaseEmployee' @@ -1759,6 +1815,55 @@ components: nullable: true description: Ссылка на скачивание аватарки description: Расширенный класс сотрудника. + BaseResponse: + title: Base Response + type: object + properties: + Content-Disposition: + type: string + description: Используемый заголовок + default: attachment + acl: + type: string + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла Status: type: object nullable: true @@ -1797,7 +1902,8 @@ components: format: date-time description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ nullable: true - QueryCommonMethods: + CommonMethods: + title: Common Methods type: object description: получение списка актульных полей сущности. properties: @@ -1811,38 +1917,39 @@ components: description: Идентификатор поля data_type: type: string + enum: + - string + - number + - date + - link example: number - description: тип поля (string, number, date или link) - NotFound: - description: Объект не найден + description: тип поля + Errors: type: object properties: - detail: - description: 'Описание ошибки' - example: "Страница не найдена." - type: string - Errors: - title: Errors - type: array - items: - title: Error - type: object - properties: - key: - title: key - type: string - value: - title: value - type: string - message: - title: message - type: string - code: - title: code - type: string - payload: - title: payload - type: object + errors: + type: array + items: + key: + title: key + type: string + description: Ключ параметра, в котором произошла ошибка + value: + title: value + type: string + description: Значение ключа, которое вызвало ошибку + message: + title: message + type: string + description: Ошибка текстом, который вы можете вывести пользователю + code: + title: code + type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) + payload: + title: payload + type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) Buttons: title: Message Buttons type: array @@ -1869,111 +1976,149 @@ components: title: Data type: string maxLength: 255 - CreateMessage: + BaseThread: + title: Base Thread + type: object + properties: + id: + type: integer + description: Идентификатор поля + chat_id: + type: integer + description: Идентификатор поля чата + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files type: object required: - - entity_id - - content + - key + - name + - file_type properties: - entity_type: - title: Entity Type + key: type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: type: string - files: + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + Files: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object title: Files - type: array - items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - name: - title: Name - type: string - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - size: - title: Size - type: integer - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - EditMessages: + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages type: object description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: content: type: string description: Текст сообщения default: Текст сообщения - files: - type: object + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type type: string enum: - - 'file' - - 'image' - size: + - discussion + - user + - thread + default: discussion + entity_id: + title: Entity Id type: integer - default: 1234 - description: Размер файла в байтах, отображаемый пользователю - buttons: - type: array - description: Массив строк, каждая из которых представлена массивом кнопок. Подробнее о том, как формировать строки кнопок и какие есть ограничения вы можете прочитать в статье. Для удаления кнопок у сообщения пришлите пустой массив. - items: - type: array - items: - type: object - properties: - text: - type: string - description: Текст, отображаемый на кнопке пользователю - url: - type: string - description: Ссылка, которая будет открыта по нажатию кнопки - data: - type: string - description: Данные, которые будут отправлены в исходящем вебхуке по нажатию кнопки + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false Message: type: object properties: @@ -2031,64 +2176,6 @@ components: title: Url type: string description: Размер файла в байтах, отображаемый пользователю - buttons: - title: buttons - $ref: '#/components/schemas/Buttons' - thread: - title: Thread - type: object - nullable: true - default: null - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. Reaction: type: object properties: @@ -2105,81 +2192,8 @@ components: type: string description: | Emoji символ реакции. - BadRequest: - type: object - properties: - error: - type: string - message: - type: string - ErrorsCode: - description: Bad Request - type: object - properties: - key: - type: string - value: - type: string - message: - type: string - code: - type: string - payload: - type: object - Chat: - type: object - description: Беседа или канал - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - name: - type: string - description: Название - example: 🤿 aqua - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - member_ids: - type: array - description: Массив идентификаторов пользователей, участников - items: - type: integer - example: - - 185 - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (false) или открытый (true)' - example: false - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - QueryChat: + BaseChat: + title: Base Chat type: object description: Собранный объект параметров создаваемой беседы или канала required: @@ -2197,6 +2211,12 @@ components: example: - 186 - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] channel: type: boolean description: 'Тип: беседа (по умолчанию, false) или канал (true)' @@ -2205,6 +2225,33 @@ components: type: boolean description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' Tag: type: object description: Для получения тега вам необходимо знать его id и указать его в URL запроса. @@ -2218,9 +2265,101 @@ components: users_count: description: Количество сотрудников, которые имеют этот тег type: integer + BaseCustomProperties: + title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' securitySchemes: bearerAuth: type: http scheme: bearer security: - - bearerAuth: [] + - bearerAuth: [] \ No newline at end of file diff --git a/src/generator1/openapi_new.yaml b/src/generator1/openapi_new.yaml deleted file mode 100644 index e844632..0000000 --- a/src/generator1/openapi_new.yaml +++ /dev/null @@ -1,2396 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - enum: - - User - - Task - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/Status' - responses: - '201': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '201': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '201': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '200': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '200': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - $ref: '#/components/schemas/BaseTask' - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: array - items: - title: Error - type: object - properties: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - properties: - id: - type: integer - description: Идентификатор поля - chat_id: - type: integer - description: Идентификатор поля чата - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: object - required: - - key - - name - - file_type - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - enum: - - file - - image - CreateEditFiles: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Create&Edit Files - required: - - size - properties: - size: - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Files - properties: - id: - type: integer - description: Идентификатор поля - url: - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - discussion - - user - - thread - default: discussion - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - allOf: - - $ref: '#/components/schemas/Files' - title: files - thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - description: Задаваемые дополнительные поля - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: object - title: Custom Properties - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] From 55f2dbacfd2d47110a6a0b9cb2573d6316b15a28 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 14:18:17 +0300 Subject: [PATCH 225/296] fixed generator1 #1 --- src/generator1/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generator1/script.py b/src/generator1/script.py index c1d9dc7..ef453dc 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -58,7 +58,7 @@ def get_base_url_from_yaml(openapi_yaml): api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -openapi_yaml = "openapi_new.yaml" +openapi_yaml = "openapi.yaml" endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) From e1c43cc5201d11e8e1e715c1feeb73739d89e21a Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 14:44:31 +0300 Subject: [PATCH 226/296] fixed generator1 and its packing --- src/builder/Makefile | 2 +- src/repository/pachca-1.1.0-py3-none-any.whl | Bin 142710 -> 0 bytes src/repository/pachca-1.1.1-py3-none-any.whl | Bin 142709 -> 0 bytes .../pachca_generator1-1.0.0-py3-none-any.whl | Bin 0 -> 124663 bytes .../pachca_generator2-1.0.0-py3-none-any.whl | Bin 0 -> 177088 bytes .../pachca_generator2-1.1.0-py3-none-any.whl | Bin 55024 -> 0 bytes .../pachca_generator2-1.2.0-py3-none-any.whl | Bin 55024 -> 0 bytes 7 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/repository/pachca-1.1.0-py3-none-any.whl delete mode 100644 src/repository/pachca-1.1.1-py3-none-any.whl create mode 100644 src/repository/pachca_generator1-1.0.0-py3-none-any.whl create mode 100644 src/repository/pachca_generator2-1.0.0-py3-none-any.whl delete mode 100644 src/repository/pachca_generator2-1.1.0-py3-none-any.whl delete mode 100644 src/repository/pachca_generator2-1.2.0-py3-none-any.whl diff --git a/src/builder/Makefile b/src/builder/Makefile index b793790..98a8ca9 100644 --- a/src/builder/Makefile +++ b/src/builder/Makefile @@ -7,7 +7,7 @@ test: build: clean pip install wheel - ## python setup_generator1.py bdist_wheel --dist-dir=../repository/ + python setup_generator1.py bdist_wheel --dist-dir=../repository/ python setup_generator2.py bdist_wheel --dist-dir=../repository/ clean: diff --git a/src/repository/pachca-1.1.0-py3-none-any.whl b/src/repository/pachca-1.1.0-py3-none-any.whl deleted file mode 100644 index e977da2d8bcad5c5d54972cbd5f3cc2edae5feab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142710 zcmbTd1CV9Un=N|E?y4@^wq4bwF59+kv&*(^b=kIU+qU)UH*eK&HXsP0d;DPG>0TG-yAj=cb5dpoJ*S4kmt zvxOt(yiNFb_CifvZ6nob7__HmuX5=0DkKXIPz$>Oek$s`Um#_Vm%$Q|RvN`v?SfIKGvpW*sZ?J+^X0wL#VpK@{SpuC|-yjYw{?G9}C}g_sN@ zOv@<9+gH)q#w}mh;+#zNm4)0b5oP_JhP6trp;2u&E|!IjbJBX9cUL&ma_mDphMG0! zmY+^EIb(!wkXuk(L2+odmNUs!At?Svna_L9^kj+D;85uzNZL!Nmf5jw^%uEP$CTCN z&?!|alc;lYZ|r$@msY-RvqUcN2oB9(o{8lP#c`T2>fY(R6q047%ETi3AZeLX#szsP zEn`F40c81!ZuZ0eRxMlyTGfnGI9ImD@)qvufKw}U6?Q?=<8Id)e~6a8y{%k&nmyH_ zt&Il=*(2AXEA`AdBTA=46mfoRN`4#q%gCoDSxr`Vm6Bo71kt46j_5Gg_U180W=WhJ zF6*2pd!gkG2M@0&)%!7KJJ-W#ty7@8%i0GYSa{qnbs@dF0@>F z8<|+m=r8dEoWa%Vo&an7Bj2j%@j;+1;~qTiuG-WQ6dh5=fknGtddpKMg9at4IMxq6 zjLJT+xvOr$UEBkJ`0Z(#Qd?&}Lt(!PA!O6KaS4!(%Ga#6WcmUh-zuiaWAGnSWbSwl zXom56z!9t#%GjbK^^W)`7KHCe_QTDyd6531X^d))}yyLkEN2;r4}xY`MR z?()$!+VU=+bMfzPS-fJAhw^Bd-d_n>x&^1k+b8z7%>#I^Ozvc%7H$Nd1*)=K%$1<875eVtL;nA@HRWeff z%dg6>=uG#gIkndhblvTU4K8h@fjvtZ@Nsc9mxy)T$-iJ;ry+-=<$I$%=W?}mR-_cq zT@dgcl}lD-mOy~}` zexSm#)lfA4X@78hX0P&eSw)b1^+8P7Z`+V|JAW>CS@fof0vEJ;A3lOapMcimJvgvq z^vIrrVa`eV_4KP@lhW5sigW0dl15;yT^9Uueq85eM6JeT*(DyOsRkHKwP~SK4$qPh z>6z1mwndyrA(=DoJ?|sc65m|QSN}Q=uo3XM6`2^8r}G0j@r!BKCDM;>^@3SnH{9O9 z5-4w{br~mxk~J$y3D!(w>y1unGk)!9wcU>-BbugVD}()_-~G{QLk`{fOxp}ay!F5} z?{3O)PcIMkK2oyhM|KY`DvNB&nd}FGz>G9IymjW3+GH2lC0CAYj}oUi(D#uOBOk|S z{o=i4##G!kYvi?6L~FzDa@i~L@xfYlOi9#0vOW)9?~d$^&Ojzgtw#oqb#``Hy@cJG znHdGMw?_NfihJ&RbXs|psS~HDRrz;EXllcI3T{;*Z-9C@9{Q|AWuYXO;(7tYT~7Qt%Z!J64_5No_q4zZ6Ka~Bu`Ni;&r`k zJ~SQ&YSxh_aGuQ{{DZ%342eiv$|R8k^#p!mA_Y!XfNJ}+?Wi)_F1S5iWs)dQ#O+^o z&jQu^6{EYl;0zMLX6{Y?*ullN@&#di6wgvSKAx2qg3`pXpWeR^x{9`j)u_&G;VxB; zk2jYNf`n0dt||v_twmNS9SfX0)9p;{6IP13kXc$p7yHcF`CD;=_e&$v3ETxTBWR#6 zVGW}fB5@icBLM;Vt6_aow4!ewqg` z+n=EU>u=Hw*&l0-d0BHCVp+Ba5W4xpFY`-CUDBt4h}L87%V)!*RQ$*COWi*X*g@(* z*^=P8mLFco?UDk*i53=kpZa&BtE=FG!vWh~=z+q3KtMK7E%81$^3O;8Erxx;faxCR z*LYfGgi|Hc3rH$Ahji%d89MQ%MvjFP{F(&niZxQRSj~OqK_y0h;z-D`ne%vLqz7bX zFeiQX+ei0LV%=V;IcX{Xb53Zhq!v{X$7WWndKf!U`wd(#QrQfI`(yL>J1$Z_RV4f7I%&Qj z=n)i2tC7Jk94am@?wL3yLvR@yS!}kNFGPz)-GWDuG2XzVP#sG+uk_WR0@Y5-T|eHI z^uE~0&cBTN8%g$MA)3y%AGf4!vCN`AxHf%ZLqC4-dA7O8s4mXRaMQ>CTynv#ZZWoo zTi2qa4(#jtb^1{r4ofqE$ifB)ikyl0WICEu(34xy9@q8?<-FbI}sWf=A zk+=L6EK&*bVWXb&D{jETW%a?m7ppppKAouw4Gp!kxqA`0Qm&g;T{z|Q?f&In*PY$V z?RDYa!{im#hv(z{-ofP6)gAVWC%8*S8c#BMd%;d2jE7NA@0ut9MeX@C=ulIzkF{hP z+H2MruM7rJo@Uv2F{wh@bu?rt6atp5K0k1t#k@pJe-wdor>8{bSGc%UXk}Egx-pq( z5?h85H+bW^ZBozEcGa09tfd;MAO!weKdEasO#$f{Vb$T`?JtN=U5t@AGzM!MT7?1| zdT+ETQu!Vu7xwdfdcDOi>1?dw+o=WD&R0>~LK5Y~=24UFw9X3t#0(*mE3q>X!CP^(mkf7a(?GYJ2z zV8y0QYoskFN5JfaB4FhRr5&PnjwZ+oL=MP1-m`Ir_+k={vdjnc9Jc9B`6npwx_6^c|y<$K<4A_1OTo9uCH)j4-w?O{veaR41a)J zZyOw55k|46CH@{`c$fc8)$RpSWTD3Vp;Eu8=nUo=Fj(PZT=M{TbYxkPTEQeDk^m0b zn0F^~i$Risq%G~h&d%R^P+T+`=Ct0i*99#=UU3MN>pmDz zT9NCUy*V9%cfUV$G5*D>=l4LqkU6(-qAUC ze70b16~d^fhOu&P4*n2&JRR0;OIpb0)oY&4!}yIh)smw6AgClu=B7}wyw>GiY(DM> zuSVD6o1$;9%(r{aXM~)8*RoDlBCdnu`23>Ipgc3I5iL5BErz&A!a$>{k86iNk!)g*AyQp*Zi0 zXDi6wVg5L{Xho?;(-o|u{*vfKxv%))K(Yn(G2CQN1zc&>!H zIFFHg90_-dwJpA-Wc*$_sdra!FG#xtWG@i5hx?4W2Z53U1I~U**n(Ld5i>J=h(+c? zuksbTXbfHWS4`1(6sH<*DsB-q8anBAs@U9+<>&Y!sBP&N7%z|S3G?_&4dY`xqgTc! z{ImxxFI@5F4{Hea4{TRAzT7XtltvIg;RyUeFzue`CyH5H+gGmF?bwv*DuiIs$CS?I zE!$JfdU0ia$n&0 zj2HQLt8CB+Y;1fC45=yNP+!Dr*~$$VgjEHq@jvKkmKkAEIa%Wo(kYG;!h$S;c@?a~ zp_tNk5ROz!7OdVSaNt)@73WGMt;Xsn{xa3fp5OfG6D^wI6vQqiGU}l9`4HQ1t?y`` zEF4_SSyW@a+?9|6KfIGPq+Wtywk++INN-c6)P8>-n7ww7EUO;HaG6C`Y%!leL>Aj$ zXE%6YGg3F*T}0QcBj6S*sk&xGPlV-DS4LHd>)c0wc9Al9g>Ze%Sd7}e!rKX(bs1hW z;A@{s92HoFgWwR56<^bY5A7p@0>eWL_N#k$gNEA?oRgc+ z$#n!Njb5f;b7o*+Qm{5mlT;vQ$Jl8}NLx*L1)yz&*2damiK|I)$U9xDzfLqBAu4HP6(3Uu>_&X_zVyw$-a98{|VF~M9%ZwvHMgt z5&iOAz`xGz?L%@MrSuwMrO;>&y;A3OT>fzeLiq^%6L+X#3yGdP;PxvBPog@;naf}} z-m2ER^V8O>U(&PwrKW)S0?YSn7P#cLxjin&kOf@|autQKLEwgSKx){F=A(VMS}hD@ z99(6^sD(|~>wq}KJ@9fj>h%W8`(`QN&buxCvl*g-1@E=bBNAk;w974Hi%FCjOMgBf zE##H9pa)8NM=~c{a~C!?nsjnBH@QTKVt7EemMzF@>tML>o&M?eHDD(DBqDI!Kp83K z3X{$PoOq7fYSe-BoKgfnP}%4#cQiHGR5QzrfBdgJ${b)7tlqnq|Bhjc@)|qm&<5R? z^f~hSL8Ch#eus?n;|YxWnb*7M=4rN82)45rT| z-~{RR*hRx>OgM+teZ#{TBLhn{zTKT4JQk%D1OAny5X7=hr!L`=tG?$p#9lyED<2a^R!=o`A7YCs!C+OyQ9%gqT)%r#-?5IbNq4|; z+s_Qcujt!mdX_s4+gRI5R^kTPPtnX&4NddYE4Mx*}+Z$S?q_sMk_-y(s`H3k=_ z-!rZF%>#Ybu0*feGdTW%1l2ET&x`2BqYr7q@aG#aZ{HT-pOXxv{cccB8_`CbEESZu z8O5VTBRZeBv!P5FUFEMQNP5J}mGyJl0M zLjfwg-?7C0N9j%U09W)&QRICOEfl6~_5`Dco|C1>6h1j1?QZ`o*?sdwORIPh9K4wo z)VN6|^?(5bGUDyMIXcyAM3{_C7gLFS5Chhgt=fWWxGa(+SynFMy%=!bNL9V}G<3!W z{8J5Yfy^Pk3e7CugyuaQbhFLanm82-WUI6nQ5_T3)d|=zy3~4A7?VssJ41rBAxq_e zvckdQ)Y)2N1Q2&2H8wy7bna>Vis}PCKc?Qn*I2WsWF5bzy2_-|${Zw{Xueug?hmh_ zcWAJwo0XZ9;2g3GVJh3*B*^K82ynFkJ__5Gaep4fplcc*gcEIA@15fO}fM%q7#b&sYTxxBPBS7!` z8iGOD+Ln#|fYH74Ly+f;!(Zu!Q7+-zH^q-DRx**iG|RybJj7COoDxpZ6UDZKCsOmo3l$$jKW4u2 zTu2>myix+~IEWz~*qKkCObEgjEr+p3C6D@DgSxnBlWV&9Q9pS(_!!q)-& z0V#V!nop}oKKFetwjM(sX6ar5wQ0sQcjJ&6GMb__1RF1XbSbCJuif^o0kfswL|X^ z!^qSMhBl7It6==hxhb#LssjX~&Q3JIJPF-rzl<%^M)#ONW0+Wxi2pXxev;9#cAo)4J;ZkZ-N>G4hZ-nFsmRo#zj{YDjWRjmN zdOGG}dnT-QVp1jMs9{=D=BOJY0`W;fg==p z(17)unSKQNjJQ+_ziA|XxYb`Nl8F2DA$7ifDAjw&_D|A#f{~xOQO6Cr zP|EL)lVgt zKTT*DW#P6|nL3O^fQI%&I3osTPM0JCECF`rkDQ0i7d$P~-}!UqbE%(X6;O9~oQ_Dd zp`FOyzR$@vM6&X)3eb?;!ozfkzk%M<3ag&O3g--mVBOZ^Dv~5%T5k1!^{vz-r2eLV z;$~u-$LFC@SMT;1NB9*<@FZTbn&iL5U?i~0-aSR)zZ*grE`AaN2%0*S%L%v~!7=MF z&T(?y{Yz0%F846bX%tp-I8$owXOfT1n16(^e)zX26ak%0pEpV%=Ec9v4w?hF+`?k+ zi;&(`QUg&5y|t$CuswV_+PVw z;=o9p!7%R1TZg+uk6Yc|8!!gN0)a3=p&As*h9D5eL6)lQEr7b+yRGvzOH?KSOIbX| z_thGRult~c)y5d%-O-(zadI@r35>u$8iDbF+N_{82pA)gP z(RTzR+w}X4iK;=6?q|;fDf}_;z>N$MVYJ!HPL%~-GvBat&E;MFdy1SN1%?lIrxb7V!`2@`EE#(Foz6-pM8_ad&ZI zaX!7|s_Fm|4qsHX6^SNjuh40w@H*Z-LN|h@Gk8J~B*xyheJ;7G$*SK_n@-F8WJ%QL zBr*zvpL%-wl;R`#$inB)7`IPo<%c{36h1@JWTEHMt@P->nq`D0MFNYnRpHAB%nPn7 zGr^CZ%v{65Z}V~+W1eq`BcQd!;U19cej7RdZ6WB|ze0<;Mj9%&Y_od-Xe{zXydEwb zJnRe)tw}7Uh9Uo2%fD6E5#!uT8b7av&DAcvB8p5)__Ge{ktyB?L{s%!4LpZ2ZIAZH zV`6=~@@`TF`o$}1ls*osx|({h(%5+(>)}d%9+sxD)r40)jNGpY0#{VUG|dDL{*;z5 z*d>p}CilbU0fHjb7C(&w7Z}a0CQOMWrH{~48P%MfG}qQ{M< z6ye+Nyn#gHRs~yg_ynQz@hjBq1&xhSaBBL39IxD8`nDxOFz~P>7;=qwztS%+UW&b1 zcy7u1Dr!910{ZEG_PGTeJe>$aDbFq{oXCxcsLqd4+L`~hvgAQVlclu6o~%$@!1Qx# zyOTVg*wk0n7~@#;;d_x9%~*E`qfh>_QSabLP{F21h1QntOD5|xfWCn!}_+^zn0b9~aPHLT@jr8y@$hCEO4W3*em=K+EJ9JXd1ei&d*Ut%$}IsY!!$O7vV- zJPi3gZNa>iq()f`)z ztBN^dijmMs(rhtI^*x&S)(Yce4Bj1r8pcyiWRwIYFU`%Rlu}`sKl{Z>a+qJoq2@hS zGzW7LWkh1?wXF+cW_UmQ9;LCKb?VvCvOXbG{E2qG7gZdcz!YaG zr!YTM=_^rH^Gtj3;9gi45P&UAGs>ec(%LqSGD%!MmQio@gsS>f6m3Y|66}gWUDF+5 zHS5|rhR#`@-f6WFhvlLfE*DqNd*f8Dv|4nX@m%m%YD-Lt4z5IX#iHTwd4u}McN_Tb zPohUr8pDwCDW%aU!nk69CSdrXJbXDgu{5?jE?UrCH|n4g?>?EaBVTgl=rGakq#>?M zs2Xvij)xr=gtOCjK4pRDFI#)IM4N-AWW`nF6dekOfn${`H#Q%gHeoH_JPA* zxZg7}LRrl0>d`8Z4VB3+>_)f~LVxsimgeeVGE?W|2J+=v$|wm0jQr>YK&)(i!T-w( z@sFXyN01na5(ofb1P1(fybwnA_BQqo-(Co<*eUZqdf36Mz;^%ZLZ}38zT99r=VdF$ zH8YIChQx)K(H$oDtAl-eLZ130r1Pu{6HE4t%qxnGhn=gQybs`^l%0J4W z9-vj0+fR#aMD6We{OO`1XXKCsVZV7>6$rY~c1lHXW;}&Z6v%aCFyH?ET^s;rZ`Nf? zxtPjv=hEoe0t#)jXM^P-L+G6VO(BT28#CU+)qDqG>q~f2xN&nmhG4iXEC@2YNt?u z>!r5flJY_!LUm{-{l$%-jf<&`Wp2tQW!YPl=9Gep<0ka zX-RCPdTZA$ez#cl9pqp48}a*o-!NWSVSRf}Fuohv|J{3H>qhJ7W@}`qpnNSwJt|Ej zFFH0ZrX)H>Cl6^0Cri)51Pb`q`2Vcu>2DjU=kN8z0{w4||Igt6ET@x#gv}Z~Y$wF9 z55A)~ps5XOxf)`Tr@B$_>=6+Z+<++@poT~cuJQRnJ|@1de>c!58oxCrUMe%mXpTkD z>W7a@FAMK^i>!AA{JhN#wuqc4KQ>@r18?m+i6Mw%VY0_^$vN%s;5yx~bq+ejQY%;`1?_74)&xeszWMyEby8+vD3Go;_(0GHP?< z_(uIP-;=wUoQ`@wYKLXC@L4iknUfOUtMQ@Iwgz_D55zzCoepL$=9u?r~qB(2jfUU$bJRl^cD)wH!3q3sC#MY-{TMGY9+h9q zi;aNkio|3pr<5H@v!_EXeCnm=i4Ij}JfQop$z!A&JW2nZl(hfe{x9yXZ`apVCsiKn7(loS_;}R<5Bce*Su-A(6^1BDX|0!|*0mgSo zz&8i|+lT-A`@a#}z*NuCK}XNpQ0Kd6ZEa-f@Spz<$bSm(4>FD@@lW$W0Dx8)06^$} z9KgWdNYByepMZ|vuxU`9h}siE=oA^{O7Ij{UfJx~H5?HggM^~>4LYY#SHo>%Vn}yP zzhvbi3IHAR0}*WpAXXtHVf-}K%gVhIR&;5zBHK&-3(hKU*mhc8HubQS1=IN_P@V+2 zJPrm7Po_BACs$r+WJlLJ;WUqWIaTGC5gO9-UqvvJ6MNt(^i5cZKK=^UtjUQw7Lov0 zE=o|e+QceX>Et-WKSg1rD}+iT6jOBE@5`gna_tV%HZ_Tcg97+K=QB_$uSL?(6l=Q5x%F3bpmY&uzb;EH~%2ipPeV3ZYUTycdE z5;V(nXXTXi&Guy^?F*LbFRca)#xlvXQpodfw6E2!3-_t%`Dwg^Kd9LcCFP26Wf&q+ zkqeAksB7mPkC80g$Mmc$cOE(fAIVtCL})tm#teJ;^bcu2?YUD2O#sm+OQIz|1)$D21ma z(kRl%q70IgffmlXE;4gm?=@;eXX8;-r&@` zPpp;;U%WZWBQzDO+Jp^ek|-UKZ_21c$kTWi4TDSWq5RMMW_bsgKkedQpqqc#w5nv`6jPdF$PCV(3v&NHQOrh1C;;GpPBJD&j{iXbg-RRdYxKyS@cTGFTEZj_lVYg^ z!3!g-=o@DmR0`3jlo6{!GsJFJ<)PPFv%}#Ab)P%}>n%*x*6vaE*;ZqXILzaxEAIkh z9VcJzGj$r&W`ipcKtkU91E5^n8y|NIA%#ZE6B`l3HuxpEgxe)uu&zDvcLTsX!2c>} zDpD<{Lv~Fw&$K<1i z{ooWj(*}T4N2rHN?Pgl6t;)feN=;uiiQP3YJt!CM}o0jTD|XTJS-Ivn2dN=-DO65J}>j zymC}BYwg;M5F}B#JIBr7p2}jrXJ%@97+9O->4)$N+`IPyRzz+rh7LG{Kf3lpb;5d07@-qpnv2?zyu{ZCN1z2#7lw^t6(FVld}N5;udb=~mqPx476mKT?S9^&4xFa!g)BiBZhp+kYg zXNRm4w#Z2=vy{C0OtBar;b{iKVKixq9A5SgeeaMSaxF~ZJ&Im5hl9pmg|8@7CJ6&c zXIsNUz;YtDuGJrUQxSB_knPqA$jUZgzdz#W%uY|x=7r!*0wsu?uANPFHbj9_Re^|u zRk>?W!{{&AANOF=GUPtgfC_7f9(a|c;>aA9|bCRa6}DY5mr zID--8&Cv;iQka-me8`8Z+f*K%wy`6iw9G1S-&!g2bF`^!QW8PxyteRYsG1%Z-&{8cHXSEytvv`6c zpFTskfQvv1-=sK2?W46^_-53E$fNLXaJM=73D{KODX_lBr)QZPAkfJJ{6}XBUAwYa z&@sq2P}<5B(qP11K)7iB)FIeU5~eDg9UmJ4<-`p!zINAWj@2oU61IavFP``qP7XfJ zV``CI4b$${WWcc0EhRTT&uZh76h#)(FU22GS0=^f!Ez=-C9EUqN&BCB<2Q^9;OS3AK5j$(alN%x3JZ( zUMRRULY$lG3gE^H;KB;vPpn4Op%j%C%wUVC{uGrSIttH~L{d8|I}v#?{o`VGkecM> z)TBpDjQYgafq|_`nxd6all&Cqiwa}=YKfkcqBbjU|-ZN z3ro>y>$BPPTsVxMPtQO|4VyUM5?U%9)E+iRzwyrM_NJ9! ztZCwdnMhr=pM4ENFh1fUBU*F@MjS@|R#2E+5H=ezERUEM$YU9lIyRUgR}FQnvRcXE z)_^&&wy?yYKWJ1(Gn`@mGdrq`o%@ASbIcyz`@$X9m|@yOMs?y zgpI(;`xb&l^#$t!2D^4OYhX_As z$dLH|U6GB7ucMAE2n5K3cF2{UC{c{Ha)~XH*4Y^^HYN!82qEy_^m5_lRYan$9by=7 z4Ks0ZrHic06~L zWdNS^Yi5vlBoVwmrR_m?-w?t;uIk<&mIU{+tU=_gb}D7lo+$8=VpjaTWFZ!K^S*#^ z^*+YJztL}*tG&LqxQPrjcv|svS6;ADYNLeh*2Nh8$)id5r4#Dz$*obh9Dv|;!9fLgrr~C zr-O<_&gIRk)QnWzMGzEkxcW+SLw@(+Kzd$3WGqx-o3@ff69;Sfw2j%+on6xjkWMK<+0m~#$yc2Z z_40*UFOHtJrNF0;m%hJRG8&3xp(m%8GZWbePs8x>xGlMCa^@I~ER5Sy^i z2HY)VwU2iay6e<%^$mD{UXH-HC3sCI+(JE96gS1VO&Xx*RY8iACYRORSw^H z?u7iVx>8n?6&G#{F^Wv1KwProh;M8Y#SXAgwV%#{w?Nyl$bF2MUFtNM1e`Ln3e_;z zqOn@)VBP2Oj_TqC>lat$gUvwfhRI`y$gdt_gz!?izn+H`$49l#?roRNfv^t{@b`(6 ziFCC^%r>Ul*?`I{+=WrR|8ExH`R~Kk##+b9$kEis@c+mKwb&OD(BGSv0tz#Vc3yoBD7{4+w$vY=4C9lt)` zsBx9i1Kz3PGe1bVD#gOYRU>=$$RIvgRq+ceRzg-F1?=5!sdtC|L|GVj7=v8PRF9Nc zMM?Lza>)mp;_*JC?;4Uv2kcvw9n4kMFhsg0gk1(9xLP_&1Pe7Rz4jCpcBH`{D?jH?7$`3vavL=7 zR03`qFa+E$F``&G<5a#1*aG8IM%hL$10l0h{(cISf@ zE^qxFoGh{=SHs3EqU8csDyK)E=c}{su=-gUh6j5mnMc-z`3m*eN0Y`3kdF7#B94Ey zP8;{$REk#$s2J7=+!fl=;1SlS+vAE?Ei7(IrGsEJmK$$Y zm)qYHZp>rAc>84y?Rcr>9Vd3pBlxS#+zaq7*5dC&p4@tXO>`efPsu38VBBn34O`DF zz%#rw=n43R$)5Ag<4lHzMWSNG4kR%ra-wEzo&LOM?;n21 zm;JLV{Nt&;ukri5B>07VT7&62h2s)C6BVuk{HNMZxayR1@u~Zg=n8rYvzpyF$~CmL?6v3N-KBwRJx6)Fsu>f9}DRk;a8z|-nx@q79D_^?Kr zg3%S=OcZALxm~ZzTX3HRUU27It>ww{XT zirJAhr8F(A1QAcoY$Yz%W5Jxr*trHdQeH_UaBkjqdpM*~odHmQCq<%dxtcQ4g#uXR zHbNGQo!#s_%1g{Sw;%&+uGU{+WjH2&o~O*#jV8>G3*BHTqZ3a`SGRU#(IH2^)4p{{ zP^!lk5E!bPiyDy~t;7eXx?pMj52K`g=P-IN)$_7@a7&MiSOsRo$x};C%4Bh`mBiGE z)}$9;5TS}L>+;`J(s7X?8u-QEYX&}MHV&w3=Re&2w1;{Kg(z2`y3fXE3<^= z-^!~0nig;J_BRaQiWCGA0O0!{r-hTPrH!89Kl>1wN)y&|eE)V(5MduCM~^Zj$}a#3 zipEF6qcqHTL(1S}S=Uxnfgtb0hppa#cG)hlDxcO!>=pQc#n5)v&}1c#AZ=K2boFNJ zY}_Oh{}Yx&h5)+|>fpM4&FdrRjoaWsU5E0;7;_LL-y7Seaa(D$kN7d)y+WI6pRqsa zU75G?3==}YOhAnUj|3<*WeuKaSFU%K*tmb0S8&Ikpqx7fpf^|`Kc>U?x(x^Uw7BTS zscYX7Cmf1bZQKF=Opo}W@sI}cgvXEY_)NK1PZICCwg?_*@)m^3c`b%DT+Be|nF1Qg z$~+rzBRnQ=#2j}EkvhoIIu)0tDcj40iG>~Re5#OWKOWTh3~GCFYHU8cnt zudqy)sa4cCd#1OLJLeZHA#oAr2^FP3z8rNhdg@V2KEb%?k<>3W#E`1Cvf?NHgAuL? zEs*$-_Cau-v?h7Lkcfmw8dyf5?nE>{Pj5YOR@TM9L0eoYaa|kHLCD^b-I8Ip^Y@(* z;#%Y#ElmElk4v}b_=X?wR7g4sQn+U^W<$#ehjKc~ij#GbMJjA49>OSPynt?MNfHdF zxxwY}FCr>I4ALmttSQz#++oB`4jY$8)BG6(6@60LyN&mBb`%AM5qSPk?_G~Ln{cS% zFR(Q1oDpu*xW; z&?tJ<=+J_Ql=_l4ccSCBG$-_vP1g#611N}}!K=;q-kL7sPxT*(5q>1-XzL~=>%s!J z9Yj%fPBB*rr8Hv%4aLqq?TtIX@t$LJC8nbTP>FiFqY1+O3z8$Ny~Jc;K}$eJqd{D6 zn?OJWz_rqTE}46=WNp|A#YOzuIR3fdMgk(vYZzd+{fVhfEQbgm1CK`-4;*1JMJY0| zAb$Hgp~zg#uq48To8w-6xFsU(M1Y*E4e{>uYkz4{?4*2fOo78qecf@LF!->;gR|aY z&wFM%T&8}F>Ed)QNBix6J2n4C;Qu-tWdHBM(a7o>d~QZY|3|TTMr`CQ@D20W|9;{5 zuW|p;ng4P1Z-wWCG#10ZLwq#PkzYxgst~bER-@Fs99bH&qEU@(CC*i0O(O&WG4NB9 z@?q8hkFZeaH&`!~>sHC$11AFk6j+*IeO9(jC&pAnI`yT1MhLFZhW0opx0a62gE}bT z&VYad#qTb(nIyTYS#L1yMQxWkry4~Fat_!-2WnFWtv}aVW87obU9)D*y54`Q z%*>Tdpk8ZqG>^MyY9ox|GaVyrY&>al&7;2L33!_&VB zc(wvnTXtyl`$f7_)Qo$mSHDWL5-DLj zjNV1})IhAXq_K7q@Yw`eqIOw7<>H@>>-^ovck|12r z5!Wm)tw+~L>Z4E^+qDWe5a6&H9_fp;0U_HS{#cK&f_)9=U>W}beZ^fPtnbpC(51>6 zqdUKMo(lh5n^PTv*u>yR4|A2@pvgS|#w$!#bEyZOKAoMrJhXbyaCpK_#Yle^KC@I= ziA}#2vs${n995w80{f4z;J9k;7!Uv}JB0zv>;AVj|M#`|*ZX%`V>@zF0w2aFGyp=nS1MYSJ0yb zzl8+pCiJ)<- z8S*HC>r1WC+O&;ki0{n=%ac;!vC=l(e~!-VcR_8WfXG$B$~L9fkVs@aUsy0mr6(yG z7O#N($TH#h8?#uD)9w*m;Sg17a)hB`-K)g;j5#y;%IN**($cEarO3yIfUey2UXEC$ z76N&MLL@ie>FV~yv&IeOBWeUc<(BE>5xm2jC2@Ql%8-iY_l@<-@2si~sw=1$jer;p z(_pzC9pmqHj!PrW7MzIj6SP2PFRH`RC}rmpvl=06yRSIWP2o-#C)03#Nizlzw3Pm8 zW(!G+ds!4=A=YGrK%<#1&|r@MR}ICxI*M1iRk&3R@8Ug^Od zvaJbAGMR=LQ8rI3DXaoO8}ol=tKQdC7cYKKARfDUsb{PArbON6-WTWzaWgVjE}p~f zYA!oabusKFuPSBdU4aWQPI4#xYSU8djeErT89V>c{nRV=;4)X+J8x7If;nAIy<4zJ zO|uKiqo?j*hz}eg0Mg$w^y|3GJ0$*Vqi+uv>X@*sd%*EHx9n93-y{o_CSo9)2*EqY zIM5<^iPXo1EyJWNMBybv3>J-^>7naQpO@&=Wo`Ez15eI;z`!#0u*1W=#4m;oituWy z&>#%)<}5Vyl4^tkIlj@ni?4)vr+^l9&sJ#=9;nB3uq~|&$m^)}jNjOUo6mCHhR6nC zh>o)^;K`D&nbceL~%yBk0ZN6gu4P5>Yg={-B7Z)Rof6XVB5q&Zs00T@Y z#D5#J{^!{L60-m6`(K1Y6X41FkJ+Wa)-4%0%pnFpv{K*_)f~ZFz(rP8K;C%rump+v zbwh+QTKFN5_+FDlAOR@aX|d)yyU8-*DWefAvqltt|k{CGAqnV3L2XlALPd4oO zz$6olpCi&V>zJ9DyMC0u=@I6Iu_EofF$dWyA51$}bq*seGRFREMzO}8mK+)Iq!Nm= zciD3KtMpf%85HGZtCG@VVFU0g*Rt0?+mOBxo?8+fTbr~f=QVZiv7zi)722^V>-Tm> zZ3yYz8jR3{zIuIq8(Q288RJ%a0%#ayeyf14TXKl(SnMFA?krmPb&z)TxvyArVEKR% zKJmUGN1QUK04;EI{-K5~6tag-cdsK*?AS2x`;03s_%1);eOa1|404`!JL%d4;+KV- z`h(21V+xy6ga=XU979CL{cLCU?6$1oYfi~&!k-2|YJ+Z}K&)jPWD#|#`LHA2Uj0PApN zkQUs!g2OOqUFv?nlXf7a*iA&3`P5#2WLrN|(37L8Acz&pckQX%ST7>4Q>!!%HZ_*b z*!MD(C0#umZEv^!Z6Qu$-OeArK^~Zfe%V7$(GC{#Odmk{>ODK%m2fjEOBJkj3D?W- zUn(jaD-?!WXZoe%D$J-_m1*FzAtQ{J%EAsg!_MvZ8bMYzJHGX}kZ|k0n>BCy5ZrEf zrE99JZWRhkV)_;36WBh}OUxgC3eBU7Sl!gRG`J_C2CYGsbdxa|g*^xQ-nzIYyowX(q1O03>AuWlA%drHj!sX(tfc&zHSzq&4eOM z0XFw%&8V7%s6>GFDGp6WCA+~mmxXsZhN$a!ESffs6Lirx{AWcUb(aJnwhgkOX5^FhGYWl%!-G^CUkWnAEW z84Ff-Fgr8hZ`yZ3!riw{2Q&3LA2Lsv_&~aNdHgA0x{yG4st@W+Y%6AlDfzXu(quw4 zL(|s5!#%?0FdENVJ#2l;^g9~A_l&l+{poU}d7E0<>zbmEknXtJy`;yHU309+TZ0NR zRR>G=H2f0^ZR~QOb3}eDT2@uP!Q&~d^|Et-xdz2uf-zv5=fD4;i%-g;Fxtr9Sq>S9 z@hW|W%^HW*n~Yi=zTvTO^aF}y9ZFDr(`1|6D;B$Jd2$3neqJ87jzM$-+D>kV@Xw3L z$pl+_3y7GkNCP_frW#cNOmM*7A|QXdvaYkXvAM0{4|)UKG8{=Ooa(!7;oP^sCFOrq z&dm@0V3IOygknlsMvgeWK7J~2G)k=7d!;Zy($BFN-MK<74f)5M?LeAB(4WAOCx8Zw z`VaA;2+NsZNG|#y*$yzDGmw-VQ#n1Y0tcH0?fA36coQtwh|KQW8(b={ui@^!Y6+dR zgKlo^vX$K~Mt}OBso0~fVg&rfz-wgQ90U7i{XvO~9e(^(XUS*WpBEz+s|Vr(%dK(d zhk}2@?Z4zY(DnSGKtRJ53m}EO{~js)AAmJ81w;}49lZYCM8LBEBm@B@8>&tS1qHALz5(Dm&_Gr3#_0n+7At(5#QYQ;A;H)dbCT&urv87s%p2MZze z$A}$Ec3LC+&w{d_g(7GoPfu>br!o>rOvyFnN$Wu+qu|_jcZlOrkSwcKVDMXOKv@Ie?z zyuOmYnRbF3PHF2_X?B`Bo?!_w8xRd%9*SgFKqcJPXbE6UeAkk;s`H~X3HTU`& zs?Cl|>;sk2x%W}F6r1aE?)B+D?3odxBd#P9nsDOC5z+ardsf3|($X&C(&tidLvUs5 zyz_|&r|!CKSI2J>lI@ARW5t8w!iTtQ{?u)Pr=#e)@eV60-#<9$+2M3G*Ib?rIL|ac zSDd4}<{i%CZ864vu%WJs;{1TDKa@b(obYX2#p%?ePmZtjpiuNeC^_G?DfY`nMhMFD zD`tFb_p23Ls{Ku#Q}ej%`BudE8+^%s?@s2AdapQA#<@qH;00~j>?0)Dr%7Ng(w&1Z z1eTM%A;&B(A2C>N?YZV}ZB90T&C@9Q4G-xP8TFdNFiRIo?>zPmg^AZ7%Kv)g87q9J ztot=>6?79i_M zVp)0N6zfu9f-4a6+Xh@8nVh&dsbal5P^qnalng)LcsaW8sLxYh63iu)jITJ6|sC$jA3~GP^zT znVfGVu&=HO%i3kDSRhC$tES$r(2owtTC~QPv|Hfs;N6Vbh3@bDQ)Nf-QT+G?X!l$Y zfPe)5mzDijw`XhR^7qv}toh9W;LP@~O}b&40BuklX_AcVQxT%%0$$h-^uAJ6*QVGZ zD~Z7G%IwsDDo;Ii6%l?6ku=ytE$Y_5e53q?dEzuS|HGw_!2v=OUoqot?*8K{_FbB0ud=$@Ava3s(aWq_TE=NE>L5i~FcJ~(rG&D841ov1c9g5EN`0j% zgYRmwGwZygCVg~)P5M=CM_yzFAk0AbqB`w+VE+=1dZj+>COet(Z|ku?@f#mPZSty+ z<7fuQ`2h83R=>73^B7BaGU@%id_AOxj3$mhkwY4v&>73vTderb_@imqO6%TEeFaD` z%Pk`Yhhrn~ws7tT6^71|NqOl(8!0|-(Pjt_-^Z9%Uga?buBFl7d#(sT#6iF;7lq#V zJ=Mi_>g*sKvFP^^Q8z2+UV)>T+~nP58N^kL(+g+=^A`3E4Wuitylz1%zf^vMJZLK)F6jb$FwAy&l zbWmKek9h$&IchunV8_&1B)`>B2=9*(je5iv;VqzvzCX+JH;w3OmCKhrndX?UO#X@4 zW}53{ygxqBVJKhtW=9@bhI3=&e{P>OXtwuQI(;YGc7f8XeU$(E6 zwcJZSSji<_p7^_@Bhm;XMJ>dllfV$=#+34yqzl;yPd9iha|00yk){&gZUJ_@Xc*f= zwgKYRE=myU+K!Ki(8xNwclv>d31)-fi5HS?kZYtZq?lDCtHPXL72SP&%v40Qj9(fd zaj?t88xm!VDN<9eYJ?$}B}bf1jPmywD0&$VBu$Z1B_?Vf2eeggAXGfK@L$bhKE&&o zW-U8$@R3o@u#{5qutv=KC!@y5iO_449J!NN;PEJJ2@5PXYwW%p z9X=yze-0jec#C;ttK=?;TN$<1$vPL9Y+F*cK;DAeKzzpB);+f!E36w=QrMzx+9b|& zu|(^}2qN~_2U)V(#-7276~#cuv~r)08ZDf9)E74@5uy+w`gff9_MCqdXYOfiSdc@U zM{h=U(49q%zQa>&ngtS>2|i*2472=QV;%`@A)aEm@u$PV8Qh0ubtzI`VLiI8`iJ`4 zSoPhNjaJKup(+&@Z=30|?)ZPQUtL$ulm&*CgsX-2C;BIeP+XqzMTlp)zdgzc7tf~5h|3`MT!)(~d2Vh6v0dh9a{{e>n9XV3pmcjj- zi>gBg;G%+2kQSD(ytExj zD_cGxxt!vDnD*#-V70?|&Ziv$D)=HY2O+4g>hh!piNAF&uLiiNkmh5U85gf`_z1(P zN`z}6D$xWdik+!BX^ZHaXJP=x_8H_6;}OdDPcAb4YxnTm_uz*-Q6GsHqLQo^kJOZ@ z`YyiqK#JcJ<7U;xP27dsXcBu8nsfqsPME8CVw8teh9$ZZ#3=NW1GY|K*+9 zugeYh2s~*_+rYo0iSXXHn;fHaP?g~3H>pqv*RAKEV6`j3h*>sj$NFjIMwiL}Ei&*j zM7~?6*T4abt4+Xo#@(nX1ekKI@a%0ify>A=^4g1aAnky>IdHRHIPjuCK7i&x$Aj;+9glWXZ;Yt z!6(Pz|0fIB|SxEsQhNqz=qF0&LIHMQwMy4?IqZ(tpqSUZ&EHl^AFjpE47MulOnE*$Jymm;M zTV^iw!Npa@;R%QuCdOmP%o1uP^mJ|*rta4AV7}hl-^tkjtTc)Jdo>AgGMczrIoP{= zb9MOdhUH(5u{5Zdsa64XKMLrI)c$XN!_>^y46xnyUpVmXfBpzSjcV4|w%!6L=-<{n zxK3qYB5h@Az-WS(<_y^AXWk~T@}(L(D>MtQ04e6sfn*^fPBLe{#F)OooI}+S_|NDP z4hxc}>4MTW4%*KSjP4dEKEJXYW_B-=meHp|v_!P&Z7B8@$B!l@Nl@VlV@qVHVp7So zx$k_v@dhwul~>qwgX<)nkVSHwmQq%Off?il@8fH_RL%hHvNW+7zpbQ6!Dv%0NnA} zgla#e6;^`GQtVt$JLj)z6Lvo@qC za2w;HWbFinz@`cfK}0eW;ZnNWqLr>+ARG8)aBjk3ZOl`VXkD= z+7o)4cDW&uH{RB*b6RURR*4vq?`UOeg}%30ew%zYcga?Ok||KSih2SYwtN-C26^Sp z=@uI=_p#w>rVQ=iVaBoC=WP0ep(sGr-nC@Ck&jN5tMkd?tl3*@5Z0qH0pcU4ii8-2 z1h@@=R8ttP&Lv5G65RYgmQ&DgH+@T8)zI>h5kdqmS6+AuItBW>NSYmCOf5EBQ`tkw zfC^=Z9l@Yzw<{utJlSs)1ufA6;mlL}+$8jJ+CLUC`_UT(U0ExvNO2X zaBi0Rnc(@$8_PBXhSye^CR!znS-xL611!V(h!nomq zfRz7lfaI@^?Eei#hBfSBH^q>?2&n%U9Vxn-`7nYJ(}9-uWpqtQvc%bLoC)3FS*H zfdnV1Ot&|wak2S6fC^o^+EIi?Sx9tg_512}DD*oivRFQ6osr;BD!>*qxomot=4T;` zKRSP*g(u0(csw{}0ebzIW{HUX%OJMdj5dNcRb&DyALVvp3M zw##{w0|OBRI5ML+h+a*#Q~k4BGiB+L7(Gv*ZK_aG+;2fln%segqV_sSuF_M)(f4ve zm~X|W_Gk@3@;Sq9(dYpJBXJRaN4N}FX?BA(mI2>L&b^BNQ4x{iiFG zjl`3kd42?h3`BGTH7lDL-V^2lZ417%g)tHtV zr>7KXdUej(i1Mw}qq(83oLakrfItwMS4jP}*Zk9;l?84v?&e6(pxEL}(V6B?5-T@2 zcS`D+m3Qc_<{2&8%<+vg!kOyO%&iyoXqcO>kLaL(cRYMpJa z*o_?_5*tMy-k+T!MmBXx-jv=vUbKQ6?KjejIfy%{+^Q;>Z=1!H?Ol2oFsrl6-obLx z9MiUZg>y(x7_S;6nMPc-wh3~qHoq(pAL0axEh+1IpV`w)HG4$at0lAy-tX7mJf8=% z6>&O`$IZBj{K*L|2^+&!6pn-O4n+;dpf_+#)J|o3mpCV=_{i!+yl*Z;9X4ZmNa%=cJ)D`KG&!t z?|(tMn7QaO^!=*3AP3zyrsP^axvH0kb&s65nOCb}dC3I68qm~7@(uOH5fqZJc6RDY z6GC}Yro=u-GV&8>CE_hSUASK_K@DPHujVpJhFSu$2N%U4KbUa}Gn>|B3SUQrJ_HH& z2*#WdMth2jJta-tN>`$t#6n+{iQ{AekHpUVEVDt3!Dr{HbsJU}cYx^WR=T73+Kghi zTPWnwTm~+9$y2?_#|#fKNry5mY|S=nsvasiKEh^m*jD+dDu&HE@c#+w>UPU}ep$Bq z1@e!`_SEkEbq1hFo`CItmH!)Lb9DHd&h!risaj(@W>XBUCpO80>pmIPtQ*+dj9O|L z29O0{EnQnM;d~`+oUvwZF6W`HULa1CU%m7`0PlcQ0pFzG(KYb$lk34k(XWE8>3e<4 zEPx%|d?=JOX$@pOpfs3iD)uBJN!zScnraLO61c zrUH{OA8sqOng}iIqR=ETp1P~Bgjh;=KJFRGS@TI!M2CNp&OfNpIqENuulL`JCftsx=%+YQMd-Ntc1Q5}2V`eiHyO z5L>9<-8^8u>oF6*mL`DdMV=etrFK?u_G26Ip^d{#JtmPgKD*Z{zs6#lfU)0U4?;1R z-vY_DPG&YMvI`eQ2aSSrdxo$BEyGz)$t{b?Eo0`I(|)$4ZnQGtH?(ddS-)e#=^q`` zHPVd@rH^D*;#Tjue^if8%!yJJ?!5hx6E`QI=&U3WMgn~leyYQHVwU}3p!(+9wB(Ad z!!j=1FjjX9{F9ZB{=RHtTw5ANVL__V4O=Eo8>@dCqD(WfmvN#cv`tAZDm`g`fM_2< zK3%o++qLF8$*1F|vEU!YUaX*}F^6*A`IrsyZcbc&iy3(yiOp9hBJ(nxaAYndcI7iE z^?Qj!Gez9O6jjAv{N}&BKv>=h-E(_ptGsh48HSr*M5~5moyb=Xsy)e9l>P+N(%zMP zVGDj^*Jt!Yy?CQOU<6*SIsa8x`Ex+tPUsBgoDxdR@-xZ}MW~n2Z@9Hr`OM02sY`1n&ATW4rfTva=*fl;%nfSY`qAL%`3d+0gm#RJZiOnRqozC48C+8+aI|F zEl}rf4Y}2}Xr$7zF5x1!_m-YA|BZq>`zNXEXS?!2Fg4SQ?ixXCogB!|-qhUK(6*bF z%XQLpT}+L$oT}GNPt{xi-f=|Km8sO`l3Lp?-$#k|^;uf|bmbHTj!Bk;KU=>KcAQU1 z{je;24lxqGmLMY4GDzs3z6VN2?cUh%#BevKvTtW@VRphY&B^|2C&9mIO>{Q1v$8ie zbN-h--7_RblP!RXp#rGbzd7mp+qwU}6ldgO^Ouo8W841lKamORl}4L;wJ9;(UY7SdTgx!cq3%W>wE^%n+a7pB@w$XvM$cc+WZ`E^>DE!nki4?Ch?n!wBB}M&Wk*p|j3IXdk_wTk`eD8N@PusmtXJ4Sn-2U?) zn^@BeWHV*YcQcaDtv6P*Si7;uiP_m#bcR)0M9gfgT0i>MHml=e!aaoAJzf?pAk#6E zau?Z^e>TrDoSI4`=mLo40iQ8E`>7x7M)ojS%}^0g5Sb*_$S~bHUzX#}+ye5$l0SYt8#QijO>jKrO?XR3 zVqdsUk}Nf-SooA;&25oE#EK_kY55mnd8IUARR!V8k(@$iz9MTSu1%VFCoKdl&Z**D zbRZRlMSgaHRrD`gMOM=^;Frx@(D0;zEwxiVRFc)?9)I#>1QTvZoctEukeXyIQ6TTa zsMLkO8_{#Mq12}w+@4Z^FHqD0pNC}+=QGczy?E(MXSE?uR$fqVe`-ABB1*d(Rhas7 zSf-Pro)wB2Q!rlhGie= z(x3nddn0UtD{$v=*QjOd*eCM90Rrm~=^`{EG>Es=i_toqu9a|rMrB|0EgTASW*_+| zf8zkmEGN=tubrknzzCSZT-S#itPTrY!eyKE0L0QDaKr1aGVRPdf>%o`A6V!?f`a*` z{B{S;Vu8F5g9zQY3sevg4W?3c`P=n_0XkKRi*kbYQjq>fpj>rPAue^xRESEw%9NS! zJJpx1yeYNSz=w-C)Oj1Z;{FrV-`sH@hGG!aRP+1bt6EC5LlPEq7#hK1#gqyIL$!5DllLaJA8u zoH|OBu|W1Kmk?ZSrbz|3aQ7G6Veos{?I*YN0qES|Xr37Fp|wSN9Di{$#t~_#2{#UW z<=awFEC~A};oAngnd9?v5d)>)Cn{*#N2=e@ssKcsx&cg%Tx4kquf8s2{=-p(vrb_m zW)VvB=SGh|>iRi?P3zac@NKjId#uaF)yUQDUm|1tMhdMHU}dKiKp=}w_vCn1w% zlYZXW?)KErH$6f z@rF1|1qY=M%j^>GW-<_d4_B+Y2s|~70!~N84!H6rcf;0hSSVTs!%F1MM7YT-gKm5p z)Tpcfr+6Z-cRFWX& zqCT9Vg{dXh_-b>#67~&k15-F9Fx5!lJX1iwD%J%>!_X#mSd31E1T&GD^tJs>ly9RDJr6rOUJ4SRASHd5bH)iDS5El`1*(PO_cZJD%yzrf4 zaIeLt9v+6Z%!B0Yv~7|$YxqF8VI{i zUZNtF6==basGpGkNXXS8z2$ZRfnTM4VzX%B6sa^8mno$1{$?2qB zE(Jxr2Qf#bi5e+#&|*}MY8z%JBBd+r7zoA~Fhnc2NJCNYR=d}QJX)V^s?X`?tvvi| zcGqL(7wgG7T#3p_+|+%vtS1`||91va?QnaGs%&RL#kHaKoBB@yzG<_BdZsJ)4t$$c z@~6l43F6>3unDgbag$s#W_j>*CG7C?i~!Ym3%R+ynUj)9Z>eJ7db8|P8*3sm!2C06 zF4cpV8DBIn>gF=khvc!8dg;O)$Ums$(69Ay@TwDuGJXpq;hDWM6%^GF6_VBfYk(Iu z&wnR+!V2R%=|kE*qg-Ngcc+{K@rZAC^LND!v_u-8br#xwute1o;0t zmTaa&TuSGm5!`=8TSA!-b&KwYbqmcs#?yD1;#G^%NjvY<$ulWe5Xv@OcBs=a$oy*N z1O5%F2zd^LTIc7b^r0^5z@R#~Ev!5^huOZ^i1sDg}FPwVBy*sR< zBxBlF-HGZruwXbC3=3uE!TiOw38)H9f(ESXKWELtB!)w;6{aAP2BqK@8@9UyNOraFcIcI0;V`ScMY`mjYTc5C-iC(h=~erXO2nYF)TOHrh<~gZs!yUQb^z+N z0_J=FJLGe8`@5Pc{@XHIl}}`)t1c3ytON}@ie4Vg8FdBSD!>>qQ?stWC=o8YNeXEY z5Joj8^AXNBc=B`Y+on|(hEDD!!1C0a{c6rvU(8Qp@-l8bW zN5jmqYf#vm$qntwZfJv9B9~Hp&p*67f=XXExeT zAvOs<9)XCnH1QBwKq&?IU`B+(7LE;NEhDDT%Q#;o;J-Qhh{3yl)os3@xFyXX!-|w)gT0t_T z?qomW;tzCu&{z95P7XTL7>`j?=Zd$K0f}YBJLTQQuy28b*R;!=^EMDfK#YYxg7R_pqQe0N z9^}S&w=Y^>^e#c835dB;6i-a{B$eKmxHUgzzdQsh?K`qg!iZK=<4@`R%~ykN$EYe7 zEL<=r#O|cC?uwg>6Re>nJ4oW0pM5N8=Qh`vEI1a3jvi~kf?w_Z6 ztp6UdaW%5|m$W8IXAf}M7Z6YaptxE77f1f}Is}{zU^K<*llG|0Xxow#f_i4j!bU<= zmGMDp#9&fTO46F@>^Lk6EODMeSAhV-QxhKsQHK%q0j3CXK@i6$_$;B5T`Z+N0Zo#2 zwC(Q2q09B)b%X0)qIw*hBsHpI=eFOik{HS1vWzD7@C;Qxzl}j5FMOLIinL6jFenEV z!ha^86xp$_>H^kV-l0sW4;z0Q;Uoe-e-{fTIS+}xRhHp~uGR0hZrvg&!2i7h3yU+e zyRFyUd3G%!9;_>PkuRl5%X}tMW|+$ts});GT=1V^bi%Dhq0)FlBH%N8Z9e!1MWh_< zhVbaQ)qO8$Sp8Y(I=2H{Wwjh+1-T>5K-Qib)%#j39DT?3S2D51>r&9ing(QdvKNmk z$Qqy$Vk2ezv&bxwSb&5+1!9RwpiZ2$tXB>MomlzXl9`(m5el5B{q2T^MEi&<7kw!s z$VKpKjJ+8{id(rE-KeuC^&S!QE^p|Uw9=+)FOBxX9dX`NDHrbe6BLqZSX3(>F}11B z86sk}7dn}_j0L7b)9+$DK|}fbznoPR#8+Q%iwn=D-dOY-lisqEVED#a9oMMIwDP*@GV7sGGn5X#2Bj^XbG@&C%BE6v_KP=pRV6sswWXF*^@4f@ zt|4{)V&0wnM!nf%{tBDz|BDdmjeme-k9cnbZL}0Zg5Wi!^rICCATWYU`Yn+9ND>Kk-(5w{RHk zp3L4{7wR&F<|*IL-NZ01k$sJ^3~w~^oJL~me~k^H1p zrxXatA<-jNl(@#niEXFka~|KsOxm1w*ukK~I3~kyTz}esxU-O1QP|sigfpxr0Fx@R z4uFTBLibetNcv9+`hdyEJ!M>vQx8A>kJ7W*vM$@h?f$Zzj{EYvUBR}DajWJwBoK1J zFJ+P$y;T_bR+q9LNEyc+zc33fQW??*yV{@E;MX`4c1ki9y z0iyH&1||Nhr2kr61B~7OTf5=92XD|EX{vNI8P7wn0)nP5%QR3=Hah^w%F%;Uo~`I2 z=d<9LQEQk1xH&{LxX8`2Pv|2KL)fvSIcyOy;3UK8S-UqMF=2GM16twOri9zFV++dSrn**2-F0Bt*x2U%9ft{7vq2h&XYzTN4Gv& zCZ11%udd!$}#^YEgXgaQIW?ygb7qtatz9A+?Z5A_O_2LHcuQo$5c_*3GDuD2R9h z4`%g8#D+z$R1u+?PUs^xBa$yolhI%Y6Gd=Cge<|XXh;hc zTo~T8mGhTv#Ls*)I*n*d!N;jV^Pq` zVwl;9Deb_Uu){&t4M}>YEv2^eqo0ga4UBF)E_1Oh@5ogGBB-by!t#fT$Zra01YF_n z>Mgs#W;1vQZuHaf#S=%5I7iSDYvamqJ=6`-Z+U*q{sb$G>^OtYx>*{Q%AIAcq1W1| zs-pzk@}cA`6w)$S4&v597uK>eQx=Hj-Y+*)D!j!Y>@TY8RJe$rHWDWsy?Mf6O;_$ zOb)>nw+|KlBEh8UPH+HvZ9TSWyHJV$f=vy)qxKi)^&hkGv3_Vdw<#ixytiO;%=gr6 z4%u*fmFY>A6`G$o*A-JrkDmlOagCr50<_`ifjjb_wleo3eEj%v)(kjc(LS0;3_@g- zFC1*+XHa+H%p~R6(ADcBW%WA3UxmOnBa>^39&8FVJ2bqzjpyg$FTYnWP|L%*O)oEC z;VBst<*K&XC#0Lh4rqAmDLM_5ECziarA%(GyOb@XdF?}{r!h}M*026KAd}q*R~iuc z4ip0jNBTE+V*i77{5PQd&%XL!&@%k@11sj z%H}AMj>6;w9vab$%@lCX=sGnqT~V-nV^X|h>*9Q6FIiVu89)3+EfdtMCPn9_yt{nj zDX)?DaQ~p>cYaJZC7xNR)R`7tW^5rU4*@?E<*n~+=G*qIK!VZHkTu?N#)Jt;nhvTW zzUWhf3l+3(l1P2m{6E7(O<9i^Nbp{6Rl^en1WmI#SY#!83?vJoA65aA_%l}Nu0T8; zseuHXkKU4j?PLT(jpT);dc;_xIAt#PJ7Q_tC`W&83ef}tQ*W{$ zOibBdDOZ=nTMNWY2oEVN3XI8pFgAX){0cJDK9HdsHoI$h5uX~~H6}hGGCwHrRPGx3 zGkJgxlX{>>m+u*~2L5Fbp6;VfassF9Fkyxn?hQW-+vLn(?$#S2IE)t}dk2B!sr`X) zfh#lr?r?gBKTKFAIasEJCYaooPNtN#tkqiIg@$?4K=)^9AQIvH=eLDqC-&i2e~BXE0^)YZEhXb6oiG7I2RXy35IWOBT=3;K%(7;9KPWp8VMO_zYq=Mv%Btr6TsAKo_XhbM4LxUz$aL) zV!BOd{iUo8N1?|;bA`X$LrD`355SD=dZjD$Af+#B$awl{J2NJPzS0`ydgrN}%Yn&xgA@*&d}+|2AM*2FI*nC9WiNMGQ7O|9nQ;qy0`M9%vuIf{s@ z6%Ei#`5A7Pndj_YIBky5cqCM*k;G_d&xVe-`(!Bbna%2amB?;s5zcDwh-_qCM#p;?-8{`R!R^k`!feo^X25Yu@TQUa4R9bRGv+gfwcQWM3^*om9s z%u+<*WHfEa6c82_&c?9gbP4MA7Wp+j0NVm#M7dK9aMOU)hgHWa@XdpZHIy#e)>9yZtkyp>V^mbq*u5XD2A?Bet0WpXh9n zgNA3J+K9N3I-k`xkpZLR;~^W@^qiPwQ@I8`zMY@p47MSFSV(R_EM!{|D!_x%V}e0 z449Pv<%Ir^>puRYC7QNB0$jQg%XXu5Ki-((7KF)=65SN35d>NX(^xt`;e44Bt=(z2 zWydjZjR*^gKy(MfH-uz1BqHV+lEYc>HhXOvDjl#l7~Oe(QBiwQ+iiIPlaj@$q$a=Z z{9?-S{fk`DYjmVAMD6~eB(GHCGbu-LKPnWHU4D|fEANFRgwD)|4<{B*YJ)e?#*7FG zq%*V0Zo5I)V40g*TPglLxQT8&g}QZaw&@Z|T=%8KoUcC9v-+vNh`g$tnshuYENo@M zMGQx_QD?(=6e1+g-fdo!BnN>{NX$pq1=Yz(5Jl3EY zrUdBGp?Wam#a2{bVpex~;rRy2G3qV$4mk^Wth{W$o3lr_2$#LH?iNjzoZjZaCp6)t1?FT+g%d6!K&IFGjV0!HI* zYX6s9;IMcHd=T*!4R?#jNrl@XJ8bQg;XkE)2VDZL8XJ3h$9!vOq+{E*ZQJT3oup&icE`4zj=uez`@Ziz=ea+=bMCl5 z));$?z5mqOYt33!HER~mU_Mpn+B=os&=+j|nol%MzU}r)}*WZ2hX_rl$>*tyO$cTi4DHC`B*wIiLz%SiMyfJZ)CR zlLMiR(dmZyJsE1}x0d!da`qt!g*-4&;Z29`puZP(uKvIxvuETbYpUu0XUx2Q@ba%k)YtgTI?9)sN}o1apP~C=%!K69M2pM z);rxBbh^~40!=ktDi7XV{#P+%wTWAc+Ss#3n$`YH!ny_MciqY$R%Q7e>Va@*6Va+$ z3tlUswe3hfTu4K#_61ca29utiJuZ6FR;12aWwCau_=n*Xy5D&zI1pPbF)nxL#nLV;^20z`h`9IY5 z2+RILIEU0&o$SO+VpaIX^dhs8=_!#zJ-&EJP4PQ`S6R(85&3%*1`ClQxize|9g5ZZYKOZwhkqSHv>6CAm5d;nSRDerLXavIM_Te!N+j z`vvuBTA`-sPOSpX%Lfw7+rbf;fgME7xoz`0giYrcqiP~Y@S0*-^rTJm!o*LjA==g;0C-`L+bzczSAds}zC_})wWVwZ{iSP$Z7JC5MC zpJu-Xc4y3*2`Kv}yxgkkPQUaX+UxFd1jlqUbfmBv7oW|6FW>@3aDu7-(=9PL-V)I$ zAe_=fEp-*>`Dz2&JH*rdRX&QyEiTTL5%K%?g=OY4_%bTRH4!AQl0pNiC6I{#=9 zw`DR_a2w-p)`d)e{~SL*n+C6EG|X9QK79I=ZfGDE<8Px=F8YFhvwz_hd_F*@UM$V5 z5y`}mliO47xP&y!rutf@pD@{(o}`;_nQ_@9Kq$4$PN~ zZfhjjW};F5#s!0x?UqnVp-No4es(`I5_O&nwOH@(94o>QN6W1;{So~m&2>)q!ruSe zA4b=2S6_ZT+nX15dXP)#{@qaYKNhl?#1+|h|uiR5WEHzB?YH=BLveWB@&d3WAe==qkLv{$5u;eak=hUB$NDYI~dNRkp z5{XQfK>noIhf{t&D?&cBOd>8o{zD1Iw{8zo;m4lNE$;h^CF&wv9DcbN%QxpBuKtWi63!$XS<6g1agxWsxh!Q*Kha3Uq?_6HTh*K%C>GEG} z2TTaWuO#sNk@gFXEK;=8avFQz*=js2wH-hect03tmCS~fa&J?%*O(I@Q#OayWtrWS6NAE(k!3V#R_Miub!oJ>vK3eF;uO6yODV+_ zAdHX7LFU-G{m(RUx9KT-Z%S%XtksLgOysRE6wfO7ZJIUg8qyyaua}}&Juz1kN91Y0 z-K?6E4}aUs+2f18$575BNewAk;V3ygZ<5Pw5algQ2>FU>OtoG9L>1Z8okqTKR-8=Hdu=3u zDf z0_)M3v`6pAu0pZZQ5zB%vhT?5|GYRh?*_<)AvGaMa^+K3Cs^~dgB~-4lJ|13V(jD% zC-h@>sImyS6Hn<5|LQMY6F&27N}R0$L2kvQBFQ1ls_SQ5A|bJth#nWf3{_|hyWxX^ z5^5Tj83Wmoz!Qf{A}?-wO;{j6NW|bP73H4Axyx#lX^hwb=0=&h#*E?Q(|iCyw%&&f zt0uU0#%`wmq5k#?9?AVo6vyo%KRp$5UB~s<0CZ4y3(x$SwYEnFt$#2 z-cFGGiW(&=$znCl0DWL}Y*uSowFDAaBMg$fqAhT8gyvH(>a<{Nc~nP{$Wk3fJ7iyG zNev1QJ}p~yd=puB3@hc}4C2usp-)XnY(!c3y}RR;@Ly5)^e12h5Fq9J1HeQ6H_Fog zg}O$D&i|8K0nm^CM|-h7N$}f289YR433=C~T<#VYsflGLk7}CgRO@1hu)7WwTd78u z4K%ec5ast@({?LwFvT3Fqz{u8Cb1^J9Yw%9mM3%WbFbg6%sjavyC*H2AYAfFxxz=r z=0oRLNcF+mU}sRWC>TP3_doP{IFj#xkGXyflCl&-2L=TGeEM)ImT?i6!oyCo>Jq_+ zOMv_hE#UpcQMrTD^#t0(L(XYeyB`pjJ#;*FPlzw<(Z9G>)E$8PzRg!RQiA z?Rmpte7-4ZwW)U6tFE&1Jbg2LjUnWHpACgX6v)Er&N)0Kx%YH<@^3Fb`6Acf^o?rO z$wr(BCL?y7xM7nsHoZq&Y$e3;#GtJ+twT~@>a77w?;T=fm<-B5Ht#{|J$eN}bd$p0 zosSS|&KPFn9o*G$f&E=9GTIYJ?^BHzJ`Qw z0P&{sXj3^mdK}5k4NY%}9#Ce0UEw|ft|ZD81y-MbXesU_U;ju{L`+z0U7O>oJd`8B zE=TpupDdJI59^u5$XB_mTG%%R!uxobHzmpIyb~O+lX3aBWrTC>Kol@l@<_$9VfS7j0lzAWbl(u(cz2`$RKv`GPNrHg!$!6D=vF zPaJGONU}_uTjN| z)LnUVjZkevt@MJxCvvTZKhY&g5vk^WF>JNG+$>`dFr$_}H$Go64&!4RgwR3!{h z<5(Ea-I)Uz!xg-i{l7qO7<}*tVLPJ>piR##vobiw-Ld*wX+Fy8BL>5LEwKfEe;r9> zQ1JG~8*sFDmR*Fyhy@TtYxX?}~ZOoa`M; z0g32;%tB68?Xy}J1VoDOh|%&W6@P$&rRV1fL<;2@DWJ4Eq|?VcggY1_kf;i0MPT{L z@{y(Ci7n^#H34Fa5@}sYschdyS9$EWyjg!0cP7CWohL=B^kbG*vvHxhN|w2fZI!A? z#(}3B0WwHV(Xvgos<0(=$3cmziC{CyM+Q(?&gzPgkzXyW z(tFGC*K%D6lZVQ)tKNw;PfnGMx}B9KV>DBlcOco!1o#hhrealS*y9;75@7s!$C)zD zrha|*sClWcU7uF!UQybre;HrCc#AKYHvV6K1b=2Q>Q(jhw zu+`B}7#^gUh>sv0eg>R^cnD-$I~&*TJb(O29#~KEk&Pxlzoq(4JVVaeq3vI<+uLwv zDq>i}Cr@cI1I>nsyCtYt9^SzHT~(TTB|tK|WaC?sV%{lsfrxjwO%#u9K5Xs&ie;gu z~WLzQtha^sVMy6D7U-fI-Pr(ho6wWHfQ4k~Okr!BTy?pnxAJgyim6|=$fg%1=K zy-b!>SXxovc<{*l^mH!MOpSeQL_)UrmFnVDzGsftaw`4InEjbI33yPV=}%Pjg$ZfS z6Lyb)js}B2T_qiTt75j|$>>a09d*A>p>^YEaBV0NW}3qG*8+-V)0zk$!la6o)4J(- zY+zu+j@pI3rNRRr*BwZO>0C`hvGlcW+oG2lAI>MevrH-oO? zEp=S+ED~zgxScCGgvz;d7?T=_#Otm>MFvejk&jU?=>8H*GBA?_VykBaLJMxYn&7Qw z3O-0?=<*8Sx6$V%3RIR*W|BB3B>8yTj8IbN)s;~Is{7KAq6n35QyjQ(rjGtl2L{t? zi$95x@c-KkivyDLA_KtLrv(H??EiLP^bZ&PPx|Fen%mYJ;z)iRFaDZW8P{5Ry*~0K;v*G+`(hJ=fwNkPhWX)gTrvhge7NsAB zOHv4nr9v%#jmT>+4IGT=gzmLw%*57LXXp^%Wq|Lsl z#dxq5Xd3I{lr_qh{h-_4THDHEb{3dfsBT6$p^KruW!>9t)qu|^_>~|Y7&5pG|6_kL zIY2zqdB=RQ_+Bifn(DFt#V|vKapJ@0Hf)Q>ME7}yX*fg1G`nd+0 z+7CQzVXxCiJ12EpP4>n|i6C(gMYo4G{s;BW4fQ)eG0*lNCJk<4LazQkI@w(d$(F3Q!{FJ$@m~1Xr;YyGr+dKD-9us@8N5?nY zSGs{`vrA0s{wFqV~)c`cD3FB|z zI-98#j@C2KI0Myb@ai?K4wq(5rjXt^agmWid4qaEETUi-M|sBWU>yOVZ5q^SDfOoL zFsAlY1#f019wM#0Ldr17K--+}CDj1$4L!ZaFQJSlLuXPj+x+B$#R$(yr=$}}2!XSb zjOQ=3l;HMDHE;_L&>?5!eE^iD81 zMkIa6y4ytFNO8UL2kd!`pD`|)rWA`fPj+(5GWQ&{STgDrkL=H~we&T(0VCz67;E0E zk~qC`B`Wo&q2FkRTGmp8d(E&R6EXd6C@AO*gCGC5`AQ)z7FCPltgcaQD(^t5&@L*i zGp|13O|L@PQ8q=HQPpU1E;d%#d>A$MLkPz4vPBR*dyFYv8w~Vq8t3HAil37b-1Mr} zUrrxHP|g7_iF*Q2<(z64_?eL#+pzM#iRG13|EcFi~9qcToJ$8CI3xh1@}Wt#NX3PT-|5 zE*;1s9g2uyU3BW$VU}b?34RaJ!V<9^R*4F9&EUH>tBI^S_1JPgzWD8VA|YeiwkLR4 zXC^3ayN0Zh^+R}(+451gdP11MhH<~@&2|6{w<_*5(z%YI$xASAwgA4yE}V9~Y^smm9gRc4+YLBPDTcg9x|lKE}X2m3=UU+jtkQoaUd8Hj&GzwQh#`<0Fh^rGYl zJ4ixJRj_ZiTU=d!bRl6(#4ST#8_>uSu&zgIfw_z zwh8J>{*m9gfgqeqb-eTq6caQv8Y3j01e;xrh_3p1DD-b=j-N zzY{3YHY#lwqHE)-qSG{Llh{ri2;QX;b6dvJOd}-q9RewmEk4kezOuxUn|$1%c4A~L zy!)Xi+sR4Oxwm%mne zYLW0|hR>{qp?Ly-3Gx+Uw%yz}#;G1to6^jrK07Q9zQ#?PByp8}bQIQA*-Cigwr) zp2DW~t8g3lQD@N!qxmA;*7I$uz)coIze?w>2D5quHC-FCz=mp1QCsJv*`QJOLEFa% zQ{{fWQPSHzSq)$&28*USksf%4vyFW07M98Zu^GBUoxrWdH)q=+dK+~9oHxgRVDIAz zhIS6DwG&B|>h{VJv`OU&AIE+W*|eU+1A4Ne&7^R=8VEErGk^BDR0J-0)#Lc{d+QJ4 zzlPPvO9JyQfTG7Mpy(m@f9JFHjsO05)wgspwFQKkx$09^fC*IHj2Apm`8Ez8K(Gv_ z3NT$E!W><6eIE3-G)6MR^BA&FDat4HBTw@(`9vvUVPRxHcYKTEOn%aTT@0TR#ApB< zIH1jg>?cbeQD%8cE=g7iZ}JKD#CNtCl{U6)BJ^Mx^&2IW!3aao(djA|-UDm1Fu zbD=gSFo4K}F=*x2N_AekgRIdmy@(JZXt42hbk^MU=ZmYTN1B65A!3mrty zdOTCUTs)V-h&{y!NaGwiN+`cH(^STpfM5XAH^NHdgG#))c0^d>oMikUl2v5rdC%QZ zZNrWqeIM`l-ot@q_^(Yrer2ZkJ$jK%rKLD8 zj%T;Xr5QzUP2yqlq97Jx5e#JfRE=a+<1;LwrjCZFBE6f&b~8a!NVV3j+GV+O=7P)D zA*5NI@+!j#Nyv$V3s#;U2kqD3QB@1{M)q7;+_zA%`qCohCZ%_GAc(O$Uxn){q@dIvS2(J#$f|<3D(Pumk_*#UIhM{6Caq-ZmjC?^@ zvpIv(N2H9x)8?POdV>oaZrmb)T`A?wRS`NAM{tu8;PXX@eIUPLX&p$djpxq)eDQ^^ z`L0ar-eh>5%Q9{3nIL-E*oebT&pxQ%rO2_69c3^=?*zuxtDRW?82`R7qM zX{XC0<)Bpd9D&%Lk^oID))eISVLfeLJk>o^pC$9FVizW|kQA5l7m z>;CS3Jnsm!I%10ANFkCjW%xvX?5Ix@(7Q54Ah0m@H|F=&@t>?(z_q>rERFxC*IVDj z(8W;S#na)hd=h=!1WdmmoY-^dr^rba_#-G7xHTlTRigHaX=5eabhIbbhqt+vJ^PrH zUD6yCFjW^2MI#G>c!_N^n@ zHcL>^^#tmI2)AP3BA&t3IWB_rRZH={HLWC;Ni*L9!{>Ufol6YwiRE>APokcA2g;Yw zVEY*3RkPO%u~0Wo9NT4U6zVu~D%~kwEbATUUlDK$d0i_Jur;lKCHjB4MV5AM0Lc5_ z-JtX_fc;=X`fEQ164YSNAfeh7NnH%V&-p{#Ktg$?&6IDh<*MA-SbCpPsKC6F4{nv4T0AT{t7R zofAGf9E4|zR$+5y1C+H&R7EW0VBc5|?iuMKN2&jSvMz9Od0NFnE+GA z0PEk-bol2)#eWBC`cC#X|M=%)|F@;H|F9G$N(g3IjPM-kLKQ?xg(Y%lJG-*$SLRy) ztEV~ev4zn3&?^whhv)D!OB7UXl;Y}8E2GglTpHTD-FLMS-r$mnn#z2KAmLc`nIQq2 zFbVyMH=_1DT3or=JN(3cb}a5WCsb(PK28LQ9KmtXga$G;74SD!vW`Se0+9#S@bkSJ zB?_Zd^S|8#7+{{6jpo?7cpNFJ+qq9v$jFOWJz;v4nOe$hH@OR}WOO3F zJ}l14mgS#-uU*t=OR{cL$GpoMBUe#b-LB$VWmwA8?cI(V(}C(#SK;hVMZBvOOoA;N z=o9`-5*gRNMXub=WoWLfP^>zJkfYbBGd}Gk*$jmJo7F-eNo}byOUuz*F28gUwdc@`aCqBsdrW)vH#SF@Zr0s)D_Yla zyeQD~T9{wt5~YE2X$li3xv5i2xe&=28Y6D>DME!_Zt&I2^kwY#0vMs7xV<((m zu|smX;I=E1ow7F>D{LKEhk{?b{D7lrPZg6LS6AB!@Kl!1yCz>OJexJ`weZ@F(*ZNF zfp50Wci4sIZ?KJGi*`pM50cw!)kFs91OZU160rV_#)JRk z9_#;goBzja#moUv8cu8*_9MKm9NmSGh>FU_m}%RGQA~xpaos|@uczg-GcW-UVP*Im z5Cc~LEFdNLaF`Z!dzBp}H!%bQcgIC}2FqFsMvT$jl{ zjK{AKyhbK)nZB?ECJvM8x+ema`LLC#TKt)rzc^{{pLooF5s*9*Ze?fy#DZFN+mDE#++2PnBRJ! zsnhV@q;yEn3bS#4gSo?foU|aDktEg8t3bi?JbL$Wp5{27G|4N6HTXd%ZAYwaVmWQ_ z{?T&$`8)mCT>rbS-)`@{$ziWYYT|X!M&LP_G%BPSuxW5|-&oEM$e6>%d4w@uX(%u> zALgrcP>MNE(LKdPv~BAjwH=ZoC@Rks1%vuX(!n~yzDacvH2~T;4Nrby?~2o>uB>xw z6E=hPTW5DCH{rdhA_)f4)Z=3u1Z98%XkSu2Tjge?y{@MN3&hW;saYHygpHC3vIjc! zB-8YU864ouA>dLRkJF8Y>bpa(afy@8yxkc(IV=d^u$03ms3?Ibx!cCB^{s)Y+Lr(U ze>?w?!sns=Ct$q<&$^i3Q1Z{?x$Qh}EWJul15}31du?!_p@l?!qJy)6oJBSy{PGi{ zIr8NyYI0KVswQM?wJq~@h= zqgJTy-ET2WS1in?B$!_iH%8k%)(npn8e)te>V$Z%qejx+j0X5@4c-Elw|C8Lf4GeT zx50RiuW+Z5cAq%O&YOct5|aIFO2BLcV)MpT%Cere^{V_G5Wu>BUp6j&%q*R4_7$quBVlW)8c)BrIp*0dwq zc@fNZ;B?o+mGQK0=u%m}0%`p5XoP}P{7-`q8D$9M zSd{S~6LByft=o#2;`Zz%;hjE{s+q|JJdJQy7NOphX}u&dL0{@?i5R+fCIjFja8&{L zH`ACWE#}s%Q@w#%&??|HLl5-fZq1D-9srBNIhc-Ait}Q3O8s;}(p-SGIj}73Bewc{ zhJ8pDa(|Ja=o*Uu;1g|7rU>L*AD_)Z&VZg3|7I<=yvc=EB7s2LtmSN8R1C$2S+zz( zARBDcG>k6Ungv79J3lM#k6N~1TD8G)1&wW-Pz8e_m3j{c82U?dT4vROs49~rSPSwr z{!JwL5Iq6vYi;I&eBy^J4NZUb-FMc_X)6Utda+$IMog#vG|wWbj#Lr z#dlSmFwWgw)@ zVJYi#qwEj;;>I`b1Ik@SVJb%=ERg&+2175RAx5f&QZ=>9}T74f3`!qI1Q>`d+d1Z zH^r-HcU)^0ybc01YDK=Z4>8b6?3vNu`0+(1crf zy^TT<701YiFG%cok1<_0)V%59ol$V7%AvqB$wMSRNO~pQYGsoHD$mrs7TN9+#@FLb z4-ZM@y&=u11iDdacFtjm(;^Z|@+dZcV(xH9_^*%RnrB7bJb+u70W4v_axgTuFgDaT zbg66Zx^ce&dUMy1 zyje3xwtfP1C}fO~QD{iD-cPtbI~gU6+!l)dCdZfYKI24+zdevCu8um)0Q8DOr2p9W zIGH*-07Sz7iUv|OCIIACv`qlH6=`h{!h|uZIT~1XP)gfmfsR|gg9!peqR2dAJc(#t zXoE;F3FD+F*ks+;-yjQe*i-fncAoI?&M-2mqTW=H6~%L!@8Ga)<&H&0J;GiYC!e@o zIyt6TtJ87LCpk&q@u(=AS#EFFfKwBO?1H zHgAmT`tE!WTK0l^S1 z7e*x;8wB_*L85HeAyz(b6L9&tYPCfPily`53&mP;`7qme?U`g2G|E4;8=QZw*y%G)|2Q<$CJB4 zq_YZ*Us}mYV>e`km|}LupKDrEZ@s}8EyIG8=)z(u(m+K(Rl}@R)x?P`Y>3>GTMn}i zqHgZVsfs>u(k z0P@vcD#@ZstAeJuOPsdexQp{j-zpE!?Am|pT3?J;ZJKPFTk~4>+C}|#vhEz$VQ)C= z&LYAy2F>k{hZR`pVGu=(Uah#|nc(tDV{Vxa`gONs6;qXbyVx_VdvDQs6o9T@wqeby zGeDPR5ZCY>Yy!^66>!S9=;3i?lEWc9u(j*JKvtzSnI z(Q));b}yefg`ytr+_nxgk$m zV@p^WDzX(}f3gxrMeQ|8D2bn4WmAXf7aV7jX*OeN&rj0NBStc;_pxT(*s)_(qcUMh z8HVEO9{%=PN3?_N;A442^EUE5++0xz0s`DVFFP-+gqt(${8@G|@20wcP8`MWCMBXX z8b0_c30T#YOLKR~$C#q1qXxYe=~hM4!O9~ksJBXqo*kwnanKy494l3!riO&0@xgxZ z_EE#j8%L31Ec`l&F^Nq20#h%qdqG+r{uY&VKn~FPS&r1T|3<9X>iTtiTU<;X4>d%B zVPY9(*U%HbV-EbintDP5C>yiYq=a=W5OL^8s$)d%`dUt@B58+PWkjO2bnG4s{%*tO2b|pO6P%Dz1Wk&z7oK<3cRaaV zAt)QKIC?PoZPgsIkU*;(oFkM516Iz~lM-FAYd3~5C|H45l_=lF7)&}w4&s#?RoTJ> z*B zR0I~RobQnEEEArHl-Q<@&AoeqfepkumF4&&73!x6UW5dfJqP~T`t5DZ$1(G21ZUCW z7w*K_nd>?)Jazng_jP9?Y}wf?J70ZMJ_$pX*LZF3h`-x z{-y@QG9{uQ%9CzBTY>9SQIJBU%^13wXcm{`?$H|M#ywAu1780_>w9IrZCV0^L1wNS zC^i*LL0{E$8p=X2^ zn{P@d)(U{a0=EjUb%+El*?UgYl)i6^ZwS)nI=YaesK@ARfL*Q-&PYgm`(|kfS)7h0 zy%u(%bI2mr@M$8G+ElihCP7X8-Vaj=AIRRecu5mkXJna96?(RIT|1&gXa9b@P@TIA ze+i)`v%%#+(_ zOTuV1#{ml1HOJgbrxh4%&kF7bJQmyQ?XL$Q!6!G$U9i}~uirKKN1ohp=n;*4*X(fXQoC8sZeJW3=1_}tpYrn?e%XW?NTIUz#^Wc8dp1yrm( zRKH4;L94_UqS9r6q5AQBg}?8^quZdvC4$EUfQXNR3=0AqC)5)arYy3BzP#)u6}@=G z?k(o9$$@|80Vl$=qJTmxO-sQz3tJ+ z55gQ53&4bzzy8%y)xM~8CZsONJH%iG_SVmUfC;-ozN^wLJz=IOa(hwqF-_?{I@nS) zuZyPq`f!Z2G&}#k*Wy$Yu0&MIb!B}c>#a`Dd-3E33~NO>u~+z6S8^-x^v+0PYnnTR zC1zb`nim(A+!Tn&lqyri!IF|3prnNL`%WIL;ItH`3*yV?xNlO8APu1U`dz-cnd3=R z!DB?1k0C-BgLP=QaSJ=>Nn|=pV7o*tt)~Zjf|7j+DRm=LWvH_XNMM^2rQ!>R;>f2Y zM}=6z>yH~W5rIxk5oWV~);%o(YuoDzmjh4EZ?m5^*N<=ePo$0hYa>r9Pv?0hn#8GJ zkf=62tG~Pz9G|6c;o>BlM3$Qn_M!x$MX*##ks}V(=xLN`t8#&4VZWtIBkJpeC+{KB zm*iAEz#AnEDi#SxwoA#0FTyS!1*5ca!IB%Af-&k5I3R4w_w}Mgc|&XqV!Gt>_m9_` zij!?`#R4bGg(i}ytFx^6x-eWmO~WqCTa=@;I%q7PTV)6!QX$09ECi%)Kfk1tA=qV# zzgI-AEpAMl1Y^3vFN@ZIZN-n;=y8+;ofc-p=a@%hnS77QvKl#=`1Q+irvyn2RUFcI zNQ%5_mW|MTN^Bq1t+l&{`9}HLq4okL`zjMIoL?zN84qy=PyfuX>xBC3md6l{;P-{; zrH>o+)Rsy7HDJ)7A0bxivW`DG-Y@9fw!%pAD2Vg4V-8Uzv1Ly?R^!A3+-tv$7C+S8~oEJ=__?n<^D|jWg@29I3us|LrUAtqYd|Z&e~<(=HM4gz)&B?G@V^6gz*%lmKaX1H zMEfKh<-vP5Hv*6p0#n@9PD7gq=BLookYZ3KRFovx(;ASZ4cC>W3+w!!pr4@2IJh5J ze8FF1y~rjaFFjcDgg;0J?_Q^$@pGfmOvgYDXiVR+R!QVop!a(|Iic(}xLO^ruXb$_ zYwuGb_tm5c6DNa7r%|@9AH5SHP^ejz_Jnbmc*QvE<+HP z9ies0t@)vM8bv#lhhF1$yQ0Z29slvoGl}^-Uy2{IaRvQs-z` z6PzK=Sh+!SLgFr#Q9po^m`qTJ$q?r0q%0}0?a)JP7$`^WxrIckzVR63jLp%bz@7<- z9WftWWT9ied6wE zS$HL>zc4Fg72Ozpn2OV3bvsez;2%0gX({c=dD45NK2e@HZD(giAiIfsNZ)n)pp{+N zBg<^0V^(8(bQQF;B(RAvT<^OFHvw^XCXTLVSA#fSW!B#qVwocT#NkB|_s!j<;>q9D znuR7E`zO(O{K{lveZie0irsJ!e|;26#>ndIpV{n~a)Jn(t@a)>7u7>oo;&GtMFsS8 z97>t?D)lY1n-IUOlHkX*cKU(xxyU}V-$4_;cTxB?W-V`ZnjK=JCTpYPr4nKe#6`i? zGKk$?f*rApd`L38VpSi~T&`$K+}M8G8?TRPIX{DEJxTLV@X@w zAfbbdY2@rcf**ilCx^xpc71-AapfBZ?O1MhagKCB`X_rxg=h6E;v3D=>S8ABVBq@X z!a;7m*0Vv)J~<_x>=Ao#SUvO0BzbuMm^Jb3vphU~_WPS3pF2`-&w3R#{KI!14UnfB~?38*Y@?YF3F>i0u9|&S%S^Nsw|ei^wxXL zUL>2vq}gKfKQ7F(*G^ztyHn4=4@#GY`-;zuIUj0XlrpgLQWvdy)~~IEF{ZJ3fN7Ov z$P4Nc?tS@nZG^0;v&Kd4-nGy z9cvfbw!cLi2h0XU87FokRnH3y6VX9xja!DC$K2H=-v(kHl5G5_t<5d(!t>H+=agy8 z9~poypGnE)+daKO{Za9gl#|+ZJ$%keyQ*Z#ma_t`xB#OFkw!g_xv%*())&LPK^~J{8>EaVg(~Ar zigwr0S1_ok;VY*aW$IEJ11#dBM_Rf@mpFAZ&TqM0OC}U4;TdiH`tO5*ti8n<;~{{6 zLa~5==>P4r`j-|7;H1`Q{;!!o`j*>DTA&Ggp02#_t;8`QojF zu(Wg0lIaibolbZbM^bhN-{y{JZvW``B#AN7S$El;eb3Gah2-ED(>weay@5R;pEMub z{M|b)pIkBlkZ@KLV43I_u&tkPAhW;FvhYAy6+Hvkl1IjX1LG+-#(|IFrS~~*Cvtp+ zu=RuGpR0}Vb+HRMlPTep;QEVLP6FDMm z&+LI~>IKY^DodCLYOhlNxsdWQ8&iPz{fiRWmZ%NY0pxj@x>G?iH?g&Qf4Pm=+9d!gCi!tCVpIA5wQek8p+l;aUlHoC;u9!rh~Kt2hWwA zDxU$3THVwqT%W`Ho375jc_z8MerkcBOiT~{TgN+JuRkn3Bjn{tzs_CU$=r$)gy9{D z+P?W|HCdY??s+5(BMWVgAo)kX$la+P1&`c580jwwbU#b|@~+toq*?5F)dQ$YYfce5 zKtQ}?yKEn@dVIUyu-s~2B8>OWTZt}GM-xMg^0jSg;hA!4Y1_PXck|*|@#4|YzI1yF zY}BICn!K|>`~CLt{rUwDG+iU{m?@P2S|WF7CW-JSLS>^qM?ac=j23nY*p%VVw%+Lz zw~XE`m8m)wSl&0-$2B1EZ0}tK$#IdL7aTsvC_;hgDwkovxHLn@$yK&9TiZhI6Pe=M zQM*_Wd)NuD``{k~yKd$gVno;2r=;u=1Zy(kVoTSFQ7q7M(Hsq`g48wE;}KpJg`V`v zftFM4SjXHr5V2JNb!c5EIu?~+hLK8|3b9x6(o~CC6J{LM#!F5H&=9`*GDD_PV&}q3 z)Dir8-~#wg%)$sC_sWj$iOKjn1LIACdZL_cs<}}k;47>UaE$3CQtsc@2}j{s@*h@) zC}7PuTnl&VhJy-@@h`wzMY;k;%>qR^qCaNIYvti<4rMsdg~~G$rMl!QYIjO2eiW4H z@q+P~DpO=^qJqi8nTA;Gfh5EoxLUXyO}QStc49{@*;H%(gn2)_(b-KEmI;+9nNGiC z&A04>_hN+N%U;4|X4bWQ;A1dlz@SRwxTA~$wZ@7>Qlb}ErsZF zTfCInIM1v{3-i$%O%*v}Lld;s_Ns3C&;_Fx+1YaPjkGZq25Y|bc|XOeiN<|JWaM1+ z*l|Lm`kCZ{`oZ&emv)g=Hrp`ca3AD?OJ`=^r~n^y*w=R1**-Zlz8yHVqA{4ZPyJRl z9MuwH6xa>(Y2fqjX>*acWRb_f+U3VuGb05BxGeG_EZB+Mjp~tU(S>PYN92Zeg5xuV zfTJlw*ok~@^C_t#o{~E;RoZr}Je~%pRFf#U@+vDY?%kF~(DJE+KDW$57j!N~ zGDuCvb!m{~QD}vzY_Li_c$eXMr)d;DFDcJkGS1UkO*%;~&mPrTGSowCs^cpZp$<~X z^ejxPKLs7=Dqx9?kVYqOC*Eu%iL>?H?a|cS<=IPweJj2zd2SuBAlMT1kf5|P8%(Sm zL}N+NF-U4eVDBw4QPZ6J{ArJ8xs~ArYTUSt2A0=VMTtPEM0=ZPS7xhlM0%&N|4ydmvl2I)Az{xTNUNJy3?4d}vf z0oCo_9}6=8tj+kxUAy1Sn1bAI&fx>$0N%gb($)*WInWxttwtliqWH;Kx~WuJVTn<& zNaSjX{}Mliau2+m<6YT2g1wb;4~RM_sKp~M1U9g^H{MDwwxe`~FQZhmgQBKum9^DY z{3cl**G2Su5K z+YriYT%0O{Hd_{7l!ys;8XK`ZKMp%q^rvJ1D?ZG=x2j)SvXPa7W&qqG4`l<4!R|B3 zyUq7e+f~YQ64^C;44*Ah!gC52g#TdWm9LWHa~Aws?q+q5;1!+&(K*+BkL?esp?A{t zvtrpDuV;`mE*UGc=lXiP3zSA~vRIBDNO8teERH@u%TSKORV+~d3nnspIhLQN1DeBq z>1F0PbWz_iN&G@EYWr~>v{Xu@4hcvN(|%3Yy2R2 zRoe(a{zj>YLNs>tE7>lTRzAi{PA(Rc%-ETsiI*vh}>ANJXfiKIbB& zARM;>EYU@yPshLw9wrzBxYO-V_Xer5NAO036lo%{llMS;kH@u!rXPfpc0pKV)9r_cvA5qkNLP`6DHPNw(z)_!X#V=lXJh4^ zOr5*>L)-m#?QcvY5XqoEHV6oLSEtN(qn z)4;~c%ElUSUe?jn#_+fEDp6U=W*#uG3&0DiFQ^hj$jhR9l{p(Hfe8|dYSJAPR2N#~ zTc7jFT(=$#hO>~-izU$0=<5E?PMqNqKIz*1$UfcBlQ;N>byFH(VAh;*PG!z+eRxt z7beQlJDU_P{+d6|3q%&tDiwfIJNdudV=Zl+8UQi1y9taBB?@R1;niXAVf zw$KCcQKg1~AqXe&nXN)zJ~gR>P4e?dNj>Owi|iPvCABGiJ=1Yc^ODCnQ`ahkiR%m= zlyKE9b;z4qRC12X1U@Qno9Z$o5W@$)>HZWrGL7g0vMs$(82&oa0f$v{%0DL$%|rbe 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 Gzy1eUmz{S2 literal 0 HcmV?d00001 diff --git a/src/repository/pachca_generator2-1.0.0-py3-none-any.whl b/src/repository/pachca_generator2-1.0.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..1169b43ea03fd30352207a11510f6bbc45abadf4 GIT binary patch literal 177088 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�CP$1H0=GwdpE`C2BFrI!;Uc8Q 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 z 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 diff --git a/src/repository/pachca_generator2-1.2.0-py3-none-any.whl b/src/repository/pachca_generator2-1.2.0-py3-none-any.whl deleted file mode 100644 index 534db5e446f9a6f49b1d0730ac1fff604d30e20e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55024 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 Date: Sun, 12 Jan 2025 15:12:22 +0300 Subject: [PATCH 227/296] Update README.md --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/README.md b/README.md index 4d4acc2..dd91c9c 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,73 @@ _src/generator2/_ --- +## Инструменты для генерации библиотеки + + +### Порядок действий (работать в папке `builder` при активированном `venv`): + +1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** + + - winget install GnuWin32.Make. + +2. **Создание зависимостей для сборки библиотеки:** + + ```bash + pip install pipenv + pipenv install requirements.txt + ``` + +3. **Создать версию библиотеки при помощи команды (пример):** + + ```bash + export PACKAGE_VERSION='1.1.0' + ``` + +4. **Запуск создания библиотеки при помощи команды:** + + ```bash + make build + ``` +5. **Упакованная библиотека сохраняется в папке repository с указанием метода генерации кода и версии библиотеки (пример):** + + - pachca_generator1-1.1.0-py3-none-any.whl + - pachca_generator2-1.2.1-py3-none-any.whl + +6. **Распаковка бибилотеки:** + + - Для Linux/gitBash: + ```bash + python3 -m venv venv + source venv/scripts/activate + pip install <имя файла>.whl + ``` + - Для Windows cmd: + ```bash + python -m venv venv + .\venv\scripts\activate + pip install <имя файла>.whl + ``` + +### Основные компоненты +_src/builder/_ + +#### requirements.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы над проектом. + +#### Pipfile +- файл, используемый виртуальной средой Pipenv для управления зависимостями проекта. + +#### Pipfile.lock +- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. + +#### Makefile +- файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. + +#### setup_generator1.py, setup_generator2.py +- файле с описанием, каким именно образом будет упакован код для медотов генерации + +--- + ## 💡 Команда проекта **Студенты Яндекс Практикума, Team 2**: From 8fb42fb3be2c1de6c6d29f0387a5a650f584fdfb Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 12 Jan 2025 15:41:37 +0300 Subject: [PATCH 228/296] Edit README.md to describe new generator2 structure --- README.md | 72 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index dd91c9c..1011096 100644 --- a/README.md +++ b/README.md @@ -27,22 +27,29 @@ ### 📦 Библиотеки (gen_v1): - **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. +- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. - **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. ### 📦 Библиотеки (gen_v2): - **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. +- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. - **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. +- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +- **ruff (0.7.1)**: Для автоматического исправления стилизации кода. +- **black (24.10.0)**: Для автоматического исправления стилизации кода. --- ## 📂 Структура проекта ### 🛠️ Основные компоненты -_src/generator2/_ + +_src/generator2/generator2_full_ + +#### 📁 models/ +- models_response_ # Модели ответов API +- models_reqBod_ # Модели запросов API #### 🧩 bot.py - Основной класс для работы с API @@ -50,6 +57,24 @@ _src/generator2/_ - Базовая функциональность для HTTP-запросов - Форматирование URL и параметров запросов +#### 🔧 constants.py +- Константы клиента +- Константы логгера + +#### 🧪 pachca.py +- Пример использования сгенерированного API клиента +- Тестовые вызовы различных методов API + +#### 📁 logger_setup.py +- Подготовка объекта логгера для логирования результатов работы + +#### 🌐 request_methods.py +- Содержит асинхронные методы для работы с API +- Импортирует сгенерированные Pydantic модели +- Реализует логику HTTP-запросов + +_src/generator2/services_ + #### 🔧 constants.py - Константы проекта - Маппинги типов данных @@ -61,16 +86,27 @@ _src/generator2/_ - Создает необходимые директории - Управляет генерацией выходных файлов +#### 📂 yaml_loader.py +- Загрузка YAML файла спецификации OpenAPI +- Создание глобального объекта YAML_DICT + +#### 📁 logger_setup.py +- Подготовка объекта логгера для логирования результатов работы + +_src/generator2/_ + #### 📝 yaml_processor.py - Обрабатывает YAML спецификацию - Генерирует модели запросов и ответов - Функция get_all_endpoints для извлечения эндпоинтов из YAML документации - Функция process_endpoints для обработки эндпоинтов и генерации моделей для requestBody и response -#### 🌐 request_methods.py -- Содержит асинхронные методы для работы с API -- Импортирует сгенерированные Pydantic модели -- Реализует логику HTTP-запросов +#### 🔗 generate_pydantic_model.py +- Создает модели pydantic для конкретного эндпоинта + - create_model для генерации текста модели pydantic + - create_enum для создания класса Enum + - look_into_schema_new для рекурсивного прохода по модели спецификации и создания всех необходимых моделей + - check_error_field для подмены тайпхинта в модели ошибок API #### 🔗 schema_link_processor.py - Обрабатывает ссылки на схемы в YAML спецификации @@ -79,10 +115,6 @@ _src/generator2/_ - load_schema для загрузки схемы по ссылке - new_replace_ref_with_schema для замены ссылок на схемы -#### 📂 yaml_loader.py -- Загрузка YAML файла спецификации OpenAPI -- Создание глобального объекта YAML_DICT - #### 📜 requirements.txt - Список зависимостей генератора с версиями @@ -90,17 +122,13 @@ _src/generator2/_ - Генерация методов для работы с API на основе OpenAPI спецификации - Функции форматирования URL, параметров и обработки ответов -#### 🧪 pachca.py -- Пример использования сгенерированного API клиента -- Тестовые вызовы различных методов API - -#### 📄 openapi_test.yaml и openapi.yaml: +#### 📄 openapi.yaml: - OpenAPI спецификации API - Описание эндпоинтов, схем, параметров -#### 📁 models/ -- models_response_ # Модели ответов API -- models_reqBod_ # Модели запросов API +#### 🛠️ generator_starter.py +- Основной запуск генерации необходимых файлов для елиента +- Форматтинг и правка сгенерированного кода в автоматическом режиме --- @@ -118,7 +146,7 @@ _src/generator2/_ - `components`: Схемы данных для структур входных и выходных параметров. ### 🔨 Генерация кода: -- **Основной объект**: Центральный класс (`Pachka` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. +- **Основной объект**: Центральный класс (`Pachca` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. - **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. - **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. - **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. From 1c254f0efa89d10607243c90e636f6da1c72fa05 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 12 Jan 2025 15:44:40 +0300 Subject: [PATCH 229/296] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1011096..aa0244f 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ _src/generator2/_ - Описание эндпоинтов, схем, параметров #### 🛠️ generator_starter.py -- Основной запуск генерации необходимых файлов для елиента +- Основной запуск генерации необходимых файлов для клиента - Форматтинг и правка сгенерированного кода в автоматическом режиме --- From 31d0fd355f847dcef3ac0911955fe6d5c689419d Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sun, 12 Jan 2025 16:36:39 +0300 Subject: [PATCH 230/296] Update README.md --- README.md | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index aa0244f..f51ecf6 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,13 @@ - **Python 3.12+**: Основной язык для сгенерированного кода. - **asyncio**: Обеспечивает асинхронный режим работы кода. -### 📦 Библиотеки (gen_v1): +### 📦 Библиотеки (generator1): - **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. - **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. - **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. - **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. -### 📦 Библиотеки (gen_v2): +### 📦 Библиотеки (generator2): - **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. - **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. - **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. @@ -41,6 +41,29 @@ --- +## 📜 Детали реализации + +### 📄 Подготовка OpenAPI-файла: +- Формат: JSON или YAML. +- Версия OpenAPI: 3.0. + +**Обязательные секции:** +- `openapi`: Версия файла OpenAPI. +- `info`: Общая информация об API. +- `servers`: Данные о серверах для выполнения запросов. +- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. +- `components`: Схемы данных для структур входных и выходных параметров. + +### 🔨 Генерация кода: +- **Основной объект**: Центральный класс (`Pachca` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. +- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. +- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. +- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. + +--- + +# generator2 + ## 📂 Структура проекта ### 🛠️ Основные компоненты @@ -132,27 +155,6 @@ _src/generator2/_ --- -## 📜 Детали реализации - -### 📄 Подготовка OpenAPI-файла: -- Формат: JSON или YAML. -- Версия OpenAPI: 3.0. - -**Обязательные секции:** -- `openapi`: Версия файла OpenAPI. -- `info`: Общая информация об API. -- `servers`: Данные о серверах для выполнения запросов. -- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. -- `components`: Схемы данных для структур входных и выходных параметров. - -### 🔨 Генерация кода: -- **Основной объект**: Центральный класс (`Pachca` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. -- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. -- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. -- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. - ---- - ## 🚀 Установка и использование ### 🛠️ Инструкция (работать в папке `generator2` при активированном `venv`): @@ -190,6 +192,8 @@ _src/generator2/_ --- +# builder + ## Инструменты для генерации библиотеки From 1627bf89be7e0390f6645d59d523a10f0316261c Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 12 Jan 2025 17:29:51 +0300 Subject: [PATCH 231/296] test results logged --- src/generator1/pachca.py | 176 ++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 93 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index e2a8cab..8c61e81 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -3,6 +3,7 @@ import os from dotenv import load_dotenv + from pachca_api_open_api_3_0_client.client import Pachca from pachca_api_open_api_3_0_client.models.chat import Chat from pachca_api_open_api_3_0_client.models.create_chat_body import ( @@ -32,162 +33,151 @@ PutStatusBody, ) +from logger_setup import setup_logging + + load_dotenv() pachca = Pachca(os.getenv('TOKEN')) +logger = setup_logging('test_requests_logging') + async def main() -> None: """ Функция теста эндпоинтов """ - # подготовка запроса на создание беседы --> query_chat = BaseChat(name='test500_2') chat_body = CreateChatBody(chat=query_chat) - # <-- - # запрос на создание беседы + chat_create = asyncio.create_task( pachca.createChat(body=chat_body)) + chat_response = await chat_create - print(chat_response) - print('*' * 60) # запрос на получение списка бесед и каналов - print(await asyncio.create_task(pachca.getChats())) - print('*' * 60) + + create_task = await asyncio.create_task(pachca.getChats()) # запрос на получение информации о беседе - print(await asyncio.create_task( - pachca.getChat(id=chat_response.data.id)) + + getChat = await asyncio.create_task( + pachca.getChat(id=chat_response.data.id) ) - print('*' * 60) # подготовка запроса на создание сообщения в созданную беседу --> + create_message = CreateMessages( + entity_id=chat_response.data.id, content='Super puper') + message_body = CreateMessageBody(message=create_message) - # <-- + # запрос на создание сообщения в созданную беседу + message_create = asyncio.create_task( pachca.createMessage(body=message_body)) + message_response = await message_create - print(message_response) - print('*' * 60) # создание треда к созданному сообщению + thread_create = asyncio.create_task( pachca.createThread(id=message_response.data.id) ) - print(await thread_create) - print('*' * 60) # запрос на получение списка сообщений - print(await asyncio.create_task( + + getListMessage = await asyncio.create_task( + pachca.getListMessage(chat_id=chat_response.data.id)) - ) - print('*' * 60) # запрос на получение сообщения - print(await asyncio.create_task( + + getMessage = await asyncio.create_task( + pachca.getMessage(id=message_response.data.id)) - ) - print('*' * 60) - # подготовка запроса на редактирование сообщения --> + edit_meassage = EditMessages(content='NOT SUPER PUPER') + edit_message_body = EditMessageBody(message=edit_meassage) - # <-- + # запрос на редактирование сообщения - print(await asyncio.create_task( + + editMessage = await asyncio.create_task( pachca.editMessage( id=message_response.data.id, body=edit_message_body) ) - ) - print('*' * 60) - - # подготовка запроса на добавление реакции к сообщению --> - post_reactions = CodeReaction(code='😭') - # <-- - # запрос на добавление реакции к сообщению - print(await asyncio.create_task( - pachca.postMessageReactions( - id=message_response.data.id, body=post_reactions) - ) - ) - print('*' * 60) + # запрос на удаление статуса - # подготовка запроса на получение списка реакций к сообщению --> - # <-- - # запрос на получение списка реакций - print(await asyncio.create_task( - pachca.getMessageReactions(id=message_response.data.id)) - ) - print('*' * 60) + print(await asyncio.create_task(pachca.delStatus())) + + # запрос на получение тегов сотрудников + + print(await asyncio.create_task(pachca.getTags())) + + # запрос на получение списка актуальных полей сущности - # запрос на удаление реакции print(await asyncio.create_task( - pachca.deleteMessageReactions(id=message_response.data.id, code='😭') - ) + + pachca.getCommonMethods(entity_type='User')) + + ) + post_reactions = CodeReaction(code='😭') + postMessageReactions = await pachca.postMessageReactions( + id=message_response.data.id, body=post_reactions ) - print('*' * 60) - # подготовка запроса на создание напоминания --> + getMessageReactions = await pachca.getMessageReactions(id=message_response.data.id) + + deleteMessageReactions = await pachca.deleteMessageReactions(id=message_response.data.id, code='😭') + + # запрос на создание напоминания + create_body_task = CreateTaskBodyTask( kind='call', content='Звонок другу', due_at=datetime.datetime.now(), ) - body_task = CreateTaskBody(task=create_body_task) - # <-- - # запрос на создание напоминания - print(await asyncio.create_task(pachca.createTask(body=body_task))) - print('*' * 60) - - # запрос на получения списка пользователей - users_response = await asyncio.create_task(pachca.getEmployees()) - print(users_response) - print('*' * 60) - - # запрос на получение информации о пользователе - print(await asyncio.create_task( - pachca.getEmployee(id=users_response.data[0].id)) - ) - print('*' * 60) - # подготовка запроса на добавление статуса --> - query_status = QueryStatusStatus( - emoji='😭', - title='Я не плачу это просто слезы', - expires_at=None - ) + body_task = CreateTaskBody(task=create_body_task) # <-- - # запрос на добавление статуса - print(await asyncio.create_task(pachca.putStatus(body=query_status))) - print('*' * 60) - - # запрос на получение информации о своем статусе - print(await asyncio.create_task(pachca.getStatus())) - print('*' * 60) - + createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) - # запрос на удаление статуса - print(await asyncio.create_task(pachca.delStatus())) - print('*' * 60) - - # запрос на получение тегов сотрудников - print(await asyncio.create_task(pachca.getTags())) - print('*' * 60) + users_response = await asyncio.create_task(pachca.getEmployees()) - # запрос на получение списка актуальных полей сущности - print(await asyncio.create_task( - pachca.getCommonMethods(entity_type='User')) - ) - print('*' * 60) + getEmployee = await asyncio.create_task(pachca.getEmployee(id=users_response.data[0].id)) # запрос получения подписи и ключа для загрузки файла - print(await asyncio.create_task(pachca.getUploads())) - print('*' * 60) + + logger.debug(await pachca.getUploads()) + + for task in ( + chat_response, + create_task, + getChat, + message_response, + thread_create, + getListMessage, + getMessage, + editMessage, + create_task, + postMessageReactions, + getMessageReactions, + deleteMessageReactions, + createtaskbody, + users_response, + getEmployee + ): + + result = task + + logger.debug( + f"{task}: data={result} \n" + "**" + ) if __name__ == '__main__': asyncio.run(main()) From 7ff0ea33efbe052d47036fa0e6db181e5b2c9bee Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sun, 12 Jan 2025 17:32:47 +0300 Subject: [PATCH 232/296] Update README.md --- README.md | 179 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 137 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index f51ecf6..8f35886 100644 --- a/README.md +++ b/README.md @@ -19,28 +19,6 @@ --- -## 📚 Используемый стек и технологии - -### 🛠️ Языки и фреймворки: -- **Python 3.12+**: Основной язык для сгенерированного кода. -- **asyncio**: Обеспечивает асинхронный режим работы кода. - -### 📦 Библиотеки (generator1): -- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. -- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. - -### 📦 Библиотеки (generator2): -- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. -- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. -- **ruff (0.7.1)**: Для автоматического исправления стилизации кода. -- **black (24.10.0)**: Для автоматического исправления стилизации кода. - ---- - ## 📜 Детали реализации ### 📄 Подготовка OpenAPI-файла: @@ -54,17 +32,129 @@ - `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. - `components`: Схемы данных для структур входных и выходных параметров. +## 💡 Команда написания спецификации + +- [Денис Лопин](https://github.com/fantyissues) +- [Александр Аполинаров](https://github.com/Alexander-Klp) +- [Александр Тогузов](https://github.com/Imuntouchable) + ### 🔨 Генерация кода: - **Основной объект**: Центральный класс (`Pachca` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. - **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. - **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. - **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. +--- + +# ***generator1*** + +### 📚 Используемый стек и технологии: +- **Python 3.12+** +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. + +## 📂 Структура генератора + +### 🛠️ Основные компоненты +_src/generator1/_ + +#### 🛠️ pachca-api-open-api-3-0-client/client.py +- Автоматически генерируемый файл (появляется после запуска генерации) +- Представлена моделями и методами для работы с API на основе OpenAPI спецификации +- Содержит "динамическую" часть (основной класс для работы с API) после запуска скрипта-генератора +- Передает запрос пользователя в "статическую" часть, преобразовав из формата Python в JSON +- Передает ответ пользователю от "статической" части, преобразовав из формата JSON в Python + +#### 🧩 templates +- Директория хранения основных шаблонов для автоматической генерации + +#### 🔧 client_servis.py +- "Статическая" часть +- Отвечает за отправку/приемку данных на/от сервер(а) +- Полученные данные передает в "динамическую" часть (генерируемую) +- Содержит логику обеспечении безопасности и управления доступом + +#### 💾 script.py +- Создает "динамическую" часть в client.py +- Собирает главный и основной класс Pachca для работы с API + +#### 📜 requirements.txt +- Список зависимостей генератора с версиями + +#### 🧪 pachca.py +- Пример использования сгенерированного API клиента +- Тестовые вызовы различных методов API + +#### 📄 openapi.yaml: +- OpenAPI спецификации API +- Описание эндпоинтов, схем, параметров + +#### 📁 pachca-api-open-api-3-0-client/ +- директория автоматически сгенерированного кода + +--- + +## 🚀 Установка и использование + +### 🛠️ Инструкция (работать в папке `generator1` при активированном `venv`): +1. **Создайте файл `.env`** в директории `generator1`, с токеном для работы с API "Пачка". +Пример файла: + ``` + TOKEN=ваштокен + ``` +2. **Создайте и активируйте виртуальное окружение, установите зависимости**: + - Для Linux/gitBash: + ```bash + python3 -m venv venv + source venv/scripts/activate + pip install -r requirements.txt + ``` + - Для Windows cmd: + ```bash + python -m venv venv + .\venv\scripts\activate + pip install -r requirements.txt + ``` +3. **Запустите генерацию клиента**: + ```bash + openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite + ``` +4. **Запустите скрипт-генератор**: + ```bash + python script.py + ``` +5. **Установить pachca-api-open-api-3-0-client в venv командой**: + ```bash + pip install ./pachca-api-open-api-3-0-client + ``` +6. **Запустите пример запроса**: + ```bash + python pachca.py + ``` + +## 💡 Команда генератора + +- [Алексей Малков](https://github.com/shft1) +- [Владимир Кулаков](https://github.com/VladimirPulse) +- [Даниил Колчак](https://github.com/Daniil-Kolchak) +- [Данил Чирков](https://github.com/Dan1lChirkov) + --- -# generator2 +# ***generator2*** + +### 📚 Используемый стек и технологии: +- **Python 3.12+** +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +- **ruff (0.7.1)**: Для автоматического исправления стилизации кода. +- **black (24.10.0)**: Для автоматического исправления стилизации кода. -## 📂 Структура проекта +## 📂 Структура генератора ### 🛠️ Основные компоненты @@ -190,14 +280,19 @@ _src/generator2/_ python -m generator2_full.pachca ``` ---- +## 💡 Команда генератора +- [Алексей Малков](https://github.com/shft1) +- [Дмитрий Костин](https://github.com/k0sdm1) +- [Дмитрий Бурмистров](https://github.com/bura09906) +- [Павел Колесников](https://github.com/Mrclive7406) -# builder +--- -## Инструменты для генерации библиотеки +# 🔧 ***builder*** +## 🛠️ Инструменты для генерации библиотеки -### Порядок действий (работать в папке `builder` при активированном `venv`): +### 📋 Порядок действий (работать в папке `builder` при активированном `venv`): 1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** @@ -241,35 +336,35 @@ _src/generator2/_ pip install <имя файла>.whl ``` -### Основные компоненты +## 📂 Структура генератора + _src/builder/_ -#### requirements.txt +#### 📜 requirements.txt - файл, содержащий список пакетов или библиотек, необходимых для работы над проектом. -#### Pipfile +#### 📄 Pipfile - файл, используемый виртуальной средой Pipenv для управления зависимостями проекта. -#### Pipfile.lock +#### 🔒 Pipfile.lock - файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. -#### Makefile +#### 🛠️ Makefile - файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. -#### setup_generator1.py, setup_generator2.py +#### 📦 setup_generator1.py, setup_generator2.py - файле с описанием, каким именно образом будет упакован код для медотов генерации --- -## 💡 Команда проекта +## 💡 Команда упаковки генераторов -**Студенты Яндекс Практикума, Team 2**: -- Алексей Малков -- Дмитрий Костин -- Александр Малыгин -- Дмитрий Бурмистров +- [Алексей Малков](https://github.com/shft1) +- [Александр Малыгин](https://github.com/SanyM2007) +- [Александр Гора](https://github.com/MrAlexg82) + +--- -**📂 Исходный код**: [GitHub Repository](#) -**📄 Документация API**: [Pachca API Documentation](#) +**📄 Документация API**: [Pachca API Documentation](https://crm.pachca.com/dev/getting-started/requests-and-responses/) --- From b23a10039f4c0654255c4413e6eaac99ea62050a Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Sun, 12 Jan 2025 17:33:57 +0300 Subject: [PATCH 233/296] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f35886..3bf5122 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ --- -# ***generator1*** +# 🔧 ***generator1*** ### 📚 Используемый стек и технологии: - **Python 3.12+** @@ -143,7 +143,7 @@ _src/generator1/_ --- -# ***generator2*** +# 🔧 ***generator2*** ### 📚 Используемый стек и технологии: - **Python 3.12+** From 08f42bfd5a8b25af3238ff939b4f419611adaba9 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Sun, 12 Jan 2025 17:38:28 +0300 Subject: [PATCH 234/296] log file argument, logging pachca.py into pachca_testresults.log --- src/generator1/logger_setup.py | 7 +++++-- src/generator1/pachca.py | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/generator1/logger_setup.py b/src/generator1/logger_setup.py index 713bcc1..fa06bd7 100644 --- a/src/generator1/logger_setup.py +++ b/src/generator1/logger_setup.py @@ -1,10 +1,13 @@ import logging -def setup_logging(logger_name: str) -> logging.Logger: +def setup_logging( + logger_name: str, + file_name: str = 'client_generator.log' +) -> logging.Logger: logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) - file_handler = logging.FileHandler('client_generator.log', encoding='utf-8') + file_handler = logging.FileHandler(file_name, encoding='utf-8') formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 8c61e81..c6ac86f 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -39,7 +39,10 @@ load_dotenv() pachca = Pachca(os.getenv('TOKEN')) -logger = setup_logging('test_requests_logging') +logger = setup_logging( + 'test_requests_logging', + 'pachca_testresults.log' +) async def main() -> None: From 56b39f1150290a5090e81ae6f952598cbd5ec77f Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 17:49:13 +0300 Subject: [PATCH 235/296] added logger --- src/generator1/pachca.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index c6ac86f..17f5d7f 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -3,13 +3,22 @@ import os from dotenv import load_dotenv - +from logger_setup import setup_logging from pachca_api_open_api_3_0_client.client import Pachca +from pachca_api_open_api_3_0_client.models import ( + CreateTaskBodyTask, + EditMessageBody, + EditMessages, + QueryStatusStatus, +) +from pachca_api_open_api_3_0_client.models.base_chat import BaseChat from pachca_api_open_api_3_0_client.models.chat import Chat +from pachca_api_open_api_3_0_client.models.code_reaction import ( + CodeReaction, +) from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, ) - from pachca_api_open_api_3_0_client.models.create_message_body import ( CreateMessageBody, ) @@ -19,23 +28,10 @@ from pachca_api_open_api_3_0_client.models.create_task_body import ( CreateTaskBody, ) - -from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody -) - -from pachca_api_open_api_3_0_client.models.base_chat import BaseChat -from pachca_api_open_api_3_0_client.models.code_reaction import ( - CodeReaction, -) - from pachca_api_open_api_3_0_client.models.put_status_body import ( PutStatusBody, ) -from logger_setup import setup_logging - - load_dotenv() pachca = Pachca(os.getenv('TOKEN')) @@ -146,7 +142,7 @@ async def main() -> None: body_task = CreateTaskBody(task=create_body_task) # <-- - + createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) users_response = await asyncio.create_task(pachca.getEmployees()) @@ -172,15 +168,17 @@ async def main() -> None: deleteMessageReactions, createtaskbody, users_response, - getEmployee + getEmployee, ): result = task logger.debug( f"{task}: data={result} \n" - "**" + "**", ) + logger.debug('Tests ended '+'*'*100) + if __name__ == '__main__': asyncio.run(main()) From 6f27ce6e0a7922cab42d1db71d6bbc677d63c9d7 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 17:50:04 +0300 Subject: [PATCH 236/296] delete old_yaml --- src/openapi.yaml | 2364 ---------------------------------------------- 1 file changed, 2364 deletions(-) delete mode 100644 src/openapi.yaml diff --git a/src/openapi.yaml b/src/openapi.yaml deleted file mode 100644 index a2bf3a7..0000000 --- a/src/openapi.yaml +++ /dev/null @@ -1,2364 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - enum: - - User - - Task - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - - $ref: '#/components/parameters/queryParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/Status' - responses: - '201': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - $ref: '#/components/parameters/sortParameter' - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - - $ref: '#/components/parameters/availabilityParameter' - - $ref: '#/components/parameters/last_message_at_afterParameter' - - $ref: '#/components/parameters/last_message_at_beforeParameter' - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '201': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '201': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '200': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '200': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - $ref: '#/components/parameters/chatParameter' - - $ref: '#/components/parameters/perParameter25' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - type: array - description: Созданное сообщение - items: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "204": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - $ref: '#/components/parameters/reactionParameter' - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - $ref: '#/components/parameters/perParameter50' - - $ref: '#/components/parameters/pageParameter' - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - $ref: '#/components/schemas/BaseTask' - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - type: object - properties: - errors: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - parameters: - perParameter50: - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - perParameter25: - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - pageParameter: - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - queryParameter: - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - chatParameter: - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - sortParameter: - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - availabilityParameter: - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - last_message_at_afterParameter: - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - last_message_at_beforeParameter: - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - reactionParameter: - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: array - items: - title: Error - type: object - properties: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - nullable: true - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: array - items: - type: object - required: - - key - - name - - file_type - - size - properties: - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - CreateEditFiles: - title: Create&Edit Files - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: array - items: - type: object - properties: - size: - title: Size - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: array - items: - type: object - properties: - id: - title: Id - type: integer - url: - title: Url - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - allOf: - - $ref: '#/components/schemas/Files' - title: files - thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - forwarding: - title: Forwarding - type: object - nullable: true - default: null - properties: - original_message_id: - title: Origin Message Id - type: integer - description: Идентификатор оригинального сообщения - original_chat_id: - title: Original Chat Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - author_id: - title: Author Id - type: integer - description: Идентификатор чата, в котором находится оригинальное сообщение - original_created_at: - title: Original Created At - type: integer - description: Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - original_thread_id: - title: Original Thread Id - type: integer - nullable: true - description: Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_message_id: - title: Original Thread Message Id - type: integer - nullable: true - description: Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - original_thread_parent_chat_id: - title: Original Thread Parent Chat Id - type: integer - nullable: true - description: Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде. - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - title: Custom Properties - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: array - items: - type: object - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] From cd33f6adb32d1e9dd3ebd96e4cb7e76acc619d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sun, 12 Jan 2025 18:11:46 +0300 Subject: [PATCH 237/296] env --- src/generator1/pachca.bak | 184 +++++++++++++++++++++++++++++++++++ src/generator1/pachca.py | 195 ++++++++++++++++++++------------------ 2 files changed, 286 insertions(+), 93 deletions(-) create mode 100644 src/generator1/pachca.bak diff --git a/src/generator1/pachca.bak b/src/generator1/pachca.bak new file mode 100644 index 0000000..17f5d7f --- /dev/null +++ b/src/generator1/pachca.bak @@ -0,0 +1,184 @@ +import asyncio +import datetime +import os + +from dotenv import load_dotenv +from logger_setup import setup_logging +from pachca_api_open_api_3_0_client.client import Pachca +from pachca_api_open_api_3_0_client.models import ( + CreateTaskBodyTask, + EditMessageBody, + EditMessages, + QueryStatusStatus, +) +from pachca_api_open_api_3_0_client.models.base_chat import BaseChat +from pachca_api_open_api_3_0_client.models.chat import Chat +from pachca_api_open_api_3_0_client.models.code_reaction import ( + CodeReaction, +) +from pachca_api_open_api_3_0_client.models.create_chat_body import ( + CreateChatBody, +) +from pachca_api_open_api_3_0_client.models.create_message_body import ( + CreateMessageBody, +) +from pachca_api_open_api_3_0_client.models.create_messages import ( + CreateMessages, +) +from pachca_api_open_api_3_0_client.models.create_task_body import ( + CreateTaskBody, +) +from pachca_api_open_api_3_0_client.models.put_status_body import ( + PutStatusBody, +) + +load_dotenv() +pachca = Pachca(os.getenv('TOKEN')) + +logger = setup_logging( + 'test_requests_logging', + 'pachca_testresults.log' +) + + +async def main() -> None: + """ Функция теста эндпоинтов """ + + query_chat = BaseChat(name='test500_2') + chat_body = CreateChatBody(chat=query_chat) + + chat_create = asyncio.create_task( + pachca.createChat(body=chat_body)) + + chat_response = await chat_create + + # запрос на получение списка бесед и каналов + + create_task = await asyncio.create_task(pachca.getChats()) + + # запрос на получение информации о беседе + + getChat = await asyncio.create_task( + pachca.getChat(id=chat_response.data.id) + ) + + # подготовка запроса на создание сообщения в созданную беседу --> + + create_message = CreateMessages( + + entity_id=chat_response.data.id, content='Super puper') + + message_body = CreateMessageBody(message=create_message) + + # запрос на создание сообщения в созданную беседу + + message_create = asyncio.create_task( + pachca.createMessage(body=message_body)) + + message_response = await message_create + + # создание треда к созданному сообщению + + thread_create = asyncio.create_task( + pachca.createThread(id=message_response.data.id) + ) + + # запрос на получение списка сообщений + + getListMessage = await asyncio.create_task( + + pachca.getListMessage(chat_id=chat_response.data.id)) + + # запрос на получение сообщения + + getMessage = await asyncio.create_task( + + pachca.getMessage(id=message_response.data.id)) + + # подготовка запроса на редактирование сообщения --> + + edit_meassage = EditMessages(content='NOT SUPER PUPER') + + edit_message_body = EditMessageBody(message=edit_meassage) + + # запрос на редактирование сообщения + + editMessage = await asyncio.create_task( + pachca.editMessage( + id=message_response.data.id, body=edit_message_body) + ) + + # запрос на удаление статуса + + print(await asyncio.create_task(pachca.delStatus())) + + # запрос на получение тегов сотрудников + + print(await asyncio.create_task(pachca.getTags())) + + # запрос на получение списка актуальных полей сущности + + print(await asyncio.create_task( + + pachca.getCommonMethods(entity_type='User')) + + ) + post_reactions = CodeReaction(code='😭') + postMessageReactions = await pachca.postMessageReactions( + id=message_response.data.id, body=post_reactions + ) + + getMessageReactions = await pachca.getMessageReactions(id=message_response.data.id) + + deleteMessageReactions = await pachca.deleteMessageReactions(id=message_response.data.id, code='😭') + + # запрос на создание напоминания + + create_body_task = CreateTaskBodyTask( + kind='call', + content='Звонок другу', + due_at=datetime.datetime.now(), + ) + + body_task = CreateTaskBody(task=create_body_task) + # <-- + + createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) + + users_response = await asyncio.create_task(pachca.getEmployees()) + + getEmployee = await asyncio.create_task(pachca.getEmployee(id=users_response.data[0].id)) + + # запрос получения подписи и ключа для загрузки файла + + logger.debug(await pachca.getUploads()) + + for task in ( + chat_response, + create_task, + getChat, + message_response, + thread_create, + getListMessage, + getMessage, + editMessage, + create_task, + postMessageReactions, + getMessageReactions, + deleteMessageReactions, + createtaskbody, + users_response, + getEmployee, + ): + + result = task + + logger.debug( + f"{task}: data={result} \n" + "**", + ) + logger.debug('Tests ended '+'*'*100) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 17f5d7f..faf7320 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -5,17 +5,7 @@ from dotenv import load_dotenv from logger_setup import setup_logging from pachca_api_open_api_3_0_client.client import Pachca -from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, - EditMessageBody, - EditMessages, - QueryStatusStatus, -) -from pachca_api_open_api_3_0_client.models.base_chat import BaseChat from pachca_api_open_api_3_0_client.models.chat import Chat -from pachca_api_open_api_3_0_client.models.code_reaction import ( - CodeReaction, -) from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, ) @@ -28,6 +18,16 @@ from pachca_api_open_api_3_0_client.models.create_task_body import ( CreateTaskBody, ) + +from pachca_api_open_api_3_0_client.models import ( + CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody +) + +from pachca_api_open_api_3_0_client.models.base_chat import BaseChat +from pachca_api_open_api_3_0_client.models.code_reaction import ( + CodeReaction, +) + from pachca_api_open_api_3_0_client.models.put_status_body import ( PutStatusBody, ) @@ -35,150 +35,159 @@ load_dotenv() pachca = Pachca(os.getenv('TOKEN')) -logger = setup_logging( - 'test_requests_logging', - 'pachca_testresults.log' -) - async def main() -> None: """ Функция теста эндпоинтов """ + # подготовка запроса на создание беседы --> query_chat = BaseChat(name='test500_2') chat_body = CreateChatBody(chat=query_chat) - + # <-- + # запрос на создание беседы chat_create = asyncio.create_task( pachca.createChat(body=chat_body)) - chat_response = await chat_create + print(chat_response) + print('*' * 60) # запрос на получение списка бесед и каналов - - create_task = await asyncio.create_task(pachca.getChats()) + print(await asyncio.create_task(pachca.getChats())) + print('*' * 60) # запрос на получение информации о беседе - - getChat = await asyncio.create_task( - pachca.getChat(id=chat_response.data.id) + print(await asyncio.create_task( + pachca.getChat(id=chat_response.data.id)) ) + print('*' * 60) # подготовка запроса на создание сообщения в созданную беседу --> - create_message = CreateMessages( - entity_id=chat_response.data.id, content='Super puper') - message_body = CreateMessageBody(message=create_message) - + # <-- # запрос на создание сообщения в созданную беседу - message_create = asyncio.create_task( pachca.createMessage(body=message_body)) - message_response = await message_create + print(message_response) + print('*' * 60) # создание треда к созданному сообщению - thread_create = asyncio.create_task( pachca.createThread(id=message_response.data.id) ) + print(await thread_create) + print('*' * 60) # запрос на получение списка сообщений - - getListMessage = await asyncio.create_task( - + print(await asyncio.create_task( pachca.getListMessage(chat_id=chat_response.data.id)) + ) + print('*' * 60) # запрос на получение сообщения - - getMessage = await asyncio.create_task( - + print(await asyncio.create_task( pachca.getMessage(id=message_response.data.id)) + ) + print('*' * 60) + # подготовка запроса на редактирование сообщения --> - edit_meassage = EditMessages(content='NOT SUPER PUPER') - edit_message_body = EditMessageBody(message=edit_meassage) - + # <-- # запрос на редактирование сообщения - - editMessage = await asyncio.create_task( + print(await asyncio.create_task( pachca.editMessage( id=message_response.data.id, body=edit_message_body) ) - - # запрос на удаление статуса - - print(await asyncio.create_task(pachca.delStatus())) - - # запрос на получение тегов сотрудников - - print(await asyncio.create_task(pachca.getTags())) - - # запрос на получение списка актуальных полей сущности - - print(await asyncio.create_task( - - pachca.getCommonMethods(entity_type='User')) - ) + print('*' * 60) + + + # подготовка запроса на добавление реакции к сообщению --> post_reactions = CodeReaction(code='😭') - postMessageReactions = await pachca.postMessageReactions( - id=message_response.data.id, body=post_reactions + # <-- + # запрос на добавление реакции к сообщению + print(await asyncio.create_task( + pachca.postMessageReactions( + id=message_response.data.id, body=post_reactions) + ) ) + print('*' * 60) - getMessageReactions = await pachca.getMessageReactions(id=message_response.data.id) - - deleteMessageReactions = await pachca.deleteMessageReactions(id=message_response.data.id, code='😭') + # подготовка запроса на получение списка реакций к сообщению --> + # <-- + # запрос на получение списка реакций + print(await asyncio.create_task( + pachca.getMessageReactions(id=message_response.data.id)) + ) + print('*' * 60) - # запрос на создание напоминания + # запрос на удаление реакции + print(await asyncio.create_task( + pachca.deleteMessageReactions(id=message_response.data.id, code='😭') + ) + ) + print('*' * 60) + # подготовка запроса на создание напоминания --> create_body_task = CreateTaskBodyTask( kind='call', content='Звонок другу', due_at=datetime.datetime.now(), ) - body_task = CreateTaskBody(task=create_body_task) # <-- + # запрос на создание напоминания + print(await asyncio.create_task(pachca.createTask(body=body_task))) + print('*' * 60) - createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) - + # запрос на получения списка пользователей users_response = await asyncio.create_task(pachca.getEmployees()) + print(users_response) + print('*' * 60) + + # запрос на получение информации о пользователе + print(await asyncio.create_task( + pachca.getEmployee(id=users_response.data[0].id)) + ) + print('*' * 60) - getEmployee = await asyncio.create_task(pachca.getEmployee(id=users_response.data[0].id)) + # подготовка запроса на добавление статуса --> + query_status = QueryStatusStatus( + emoji='😭', + title='Я не плачу это просто слезы', + expires_at=None + ) + # <-- + # запрос на добавление статуса + print(await asyncio.create_task(pachca.putStatus(body=query_status))) + print('*' * 60) - # запрос получения подписи и ключа для загрузки файла + # запрос на получение информации о своем статусе + print(await asyncio.create_task(pachca.getStatus())) + print('*' * 60) - logger.debug(await pachca.getUploads()) - - for task in ( - chat_response, - create_task, - getChat, - message_response, - thread_create, - getListMessage, - getMessage, - editMessage, - create_task, - postMessageReactions, - getMessageReactions, - deleteMessageReactions, - createtaskbody, - users_response, - getEmployee, - ): - - result = task - - logger.debug( - f"{task}: data={result} \n" - "**", - ) - logger.debug('Tests ended '+'*'*100) + + # запрос на удаление статуса + print(await asyncio.create_task(pachca.delStatus())) + print('*' * 60) + + # запрос на получение тегов сотрудников + print(await asyncio.create_task(pachca.getTags())) + print('*' * 60) + + # запрос на получение списка актуальных полей сущности + print(await asyncio.create_task( + pachca.getCommonMethods(entity_type='User')) + ) + print('*' * 60) + + # запрос получения подписи и ключа для загрузки файла + print(await asyncio.create_task(pachca.getUploads())) + print('*' * 60) if __name__ == '__main__': asyncio.run(main()) From 6dae2aa286ea114e0df5c4a694d52d5409caddcf Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 18:18:16 +0300 Subject: [PATCH 238/296] fixed project --- src/.DS_Store | Bin 0 -> 6148 bytes .../generator2_full/models/__init__.py | 0 .../models/models_reqBod_createChat.py | 28 - .../models/models_reqBod_createMessage.py | 66 -- .../models/models_reqBod_createTask.py | 45 -- .../models/models_reqBod_editMessage.py | 46 -- .../models/models_reqBod_getDirectUrl.py | 37 -- .../models_reqBod_postMembersToChats.py | 14 - .../models_reqBod_postMessageReactions.py | 7 - .../models/models_reqBod_postTagsToChats.py | 10 - .../models/models_reqBod_putStatus.py | 19 - .../models_response_createChatpost201.py | 43 -- .../models_response_createChatpost400.py | 30 - .../models_response_createChatpost422.py | 30 - .../models_response_createMessagepost201.py | 104 --- .../models_response_createMessagepost400.py | 30 - .../models_response_createTaskpost201.py | 66 -- .../models_response_createTaskpost400.py | 30 - .../models_response_createThreadpost200.py | 23 - .../models_response_createThreadpost400.py | 30 - ...esponse_deleteMessageReactionsdelete400.py | 30 - .../models_response_editMessageput200.py | 104 --- .../models_response_editMessageput400.py | 30 - .../models/models_response_getChatget200.py | 43 -- .../models/models_response_getChatget400.py | 30 - .../models/models_response_getChatsget200.py | 45 -- .../models/models_response_getChatsget400.py | 30 - .../models/models_response_getChatsget422.py | 30 - .../models_response_getCommonMethodsget200.py | 23 - .../models_response_getCommonMethodsget400.py | 30 - .../models_response_getEmployeeget200.py | 90 --- .../models_response_getEmployeeget400.py | 30 - .../models_response_getEmployeesget200.py | 92 --- .../models_response_getListMessageget200.py | 106 --- .../models_response_getListMessageget400.py | 30 - ...dels_response_getMessageReactionsget200.py | 20 - ...dels_response_getMessageReactionsget400.py | 30 - .../models_response_getMessageget200.py | 104 --- .../models_response_getMessageget400.py | 30 - .../models/models_response_getStatusget200.py | 19 - .../models/models_response_getTagget200.py | 18 - .../models/models_response_getTagget400.py | 30 - .../models_response_getTagsEmployeesget200.py | 68 -- .../models_response_getTagsEmployeesget400.py | 30 - .../models/models_response_getTagsget200.py | 17 - .../models/models_response_getTagsget400.py | 30 - .../models_response_getUploadspost200.py | 39 -- .../models_response_leaveChatdelete400.py | 30 - ...dels_response_postMembersToChatspost400.py | 30 - ...dels_response_postMembersToChatspost422.py | 30 - ...ls_response_postMessageReactionspost400.py | 30 - .../models_response_postTagsToChatspost400.py | 30 - .../models_response_postTagsToChatspost422.py | 30 - .../models/models_response_putStatusput201.py | 19 - .../models/models_response_putStatusput400.py | 30 - .../generator2_full/request_methods.py | 608 ------------------ .../pachca_generator1-1.0.0-py3-none-any.whl | Bin 124663 -> 0 bytes .../pachca_generator2-1.0.0-py3-none-any.whl | Bin 177088 -> 0 bytes 58 files changed, 2673 deletions(-) create mode 100644 src/.DS_Store delete mode 100644 src/generator2/generator2_full/models/__init__.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createChat.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createMessage.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createTask.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_editMessage.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_putStatus.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost200.py delete mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py delete mode 100644 src/generator2/generator2_full/models/models_response_editMessageput200.py delete mode 100644 src/generator2/generator2_full/models/models_response_editMessageput400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget422.py delete mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeesget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getStatusget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getUploadspost200.py delete mode 100644 src/generator2/generator2_full/models/models_response_leaveChatdelete400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_putStatusput201.py delete mode 100644 src/generator2/generator2_full/models/models_response_putStatusput400.py delete mode 100644 src/repository/pachca_generator1-1.0.0-py3-none-any.whl delete mode 100644 src/repository/pachca_generator2-1.0.0-py3-none-any.whl diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..060543ca7bd67080d20a242e113f656237a65153 GIT binary patch literal 6148 zcmeHKyJ`bL3>+mcOx(Ckxxe5)Sd9Gz{s9LP+?X?%B=uGKu6$ZXkHY2%q;MKD0`2T- zH9BsJ(+PmBKVDbB62P49h%aBJ=J)Osd#H#J>8x?a3*K=evi6_MxlcIY4Fmmx|G7I4 z$J21&z30fJfE17dQa}nwf!ioheRaOLO*vJO0#e|P6!7muqdWG(F)=986;te$K&p;$bf^;@LFdZJb-AO)@! zc+BI{`~Q~y%lv;$(n$(PfxA+`W}Dq+%~z`4I(a$owT-@~d(JoAjr*W*iFQnkcFcpf e>;}t^y literal 0 HcmV?d00001 diff --git a/src/generator2/generator2_full/models/__init__.py b/src/generator2/generator2_full/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator2/generator2_full/models/models_reqBod_createChat.py b/src/generator2/generator2_full/models/models_reqBod_createChat.py deleted file mode 100644 index 089e9c2..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createChat.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Chat(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - - -class Createchat(BaseModel): - chat: Optional[Chat] = Field( - None, - description="Собранный объект параметров создаваемой беседы или канала", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createMessage.py b/src/generator2/generator2_full/models/models_reqBod_createMessage.py deleted file mode 100644 index a6280ed..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createMessage.py +++ /dev/null @@ -1,66 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - size: int = Field( - ..., description="Размер файла в байтах, отображаемый пользователю", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Message(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - skip_invite_mentions: Optional[bool] = Field( - None, description="No docstring provided", - ) - link_preview: Optional[bool] = Field( - None, description="No docstring provided", - ) - - -class Createmessage(BaseModel): - message: Optional[Message] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createTask.py b/src/generator2/generator2_full/models/models_reqBod_createTask.py deleted file mode 100644 index ce503e3..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createTask.py +++ /dev/null @@ -1,45 +0,0 @@ -from enum import IntEnum, StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - value: Optional[str] = Field(None, description="Значение поля") - - -class enum_kind(StrEnum): - call = "call" - meeting = "meeting" - reminder = "reminder" - event = "event" - email = "email" - - -class enum_priority(IntEnum): - priority_1 = 1 - priority_2 = 2 - priority_3 = 3 - - -class Task(BaseModel): - kind: enum_kind = Field(..., description="Тип напоминания") - content: str = Field(..., description="Описание напоминания") - due_at: str = Field( - ..., description="Срок выполнения напоминания (ISO-8601)", - ) - priority: Optional[enum_priority] = Field( - None, - description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", - ) - performer_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов пользователей", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="No docstring provided", - ) - - -class Createtask(BaseModel): - task: Optional[Task] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_reqBod_editMessage.py b/src/generator2/generator2_full/models/models_reqBod_editMessage.py deleted file mode 100644 index 8db9faf..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_editMessage.py +++ /dev/null @@ -1,46 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - size: int = Field( - ..., description="Размер файла в байтах, отображаемый пользователю", - ) - - -class Message(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - - -class Editmessage(BaseModel): - message: Optional[Message] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py deleted file mode 100644 index a4f35e7..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Getdirecturl(BaseModel): - Content_Disposition: Optional[str] = Field( - None, - description="Используемый заголовок", - alilas="Content-Disposition", - ) - acl: Optional[str] = Field(None, description="Уровень безопасности") - policy: Optional[str] = Field( - None, description="Уникальный policy для загрузки файла", - ) - x_amz_credential: Optional[str] = Field( - None, - description="x-amz-credential для загрузки файла", - alilas="x-amz-credential", - ) - x_amz_algorithm: Optional[str] = Field( - None, description="Используемый алгоритм", alilas="x-amz-algorithm", - ) - x_amz_date: Optional[str] = Field( - None, - description="Уникальный x-amz-date для загрузки файла", - alilas="x-amz-date", - ) - x_amz_signature: Optional[str] = Field( - None, - description="Уникальная подпись для загрузки файла", - alilas="x-amz-signature", - ) - key: Optional[str] = Field( - None, description="Уникальный ключ для загрузки файла", - ) - file: Optional[str] = Field(None, description="Адрес для загрузки файла") diff --git a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py deleted file mode 100644 index 59b7182..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Postmemberstochats(BaseModel): - member_ids: List[int] = Field( - ..., - description="Массив идентификаторов пользователей, которые станут участниками", - ) - silent: Optional[bool] = Field( - None, - description="Не создавать в чате системное сообщение о добавлении участника", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py deleted file mode 100644 index ba69294..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py +++ /dev/null @@ -1,7 +0,0 @@ -from pydantic import BaseModel, Field - - -class Postmessagereactions(BaseModel): - code: str = Field( - ..., description="Emoji в строковом формате для добавления реакции.", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py deleted file mode 100644 index f935dd3..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List - -from pydantic import BaseModel, Field - - -class Posttagstochats(BaseModel): - group_tag_ids: List[int] = Field( - ..., - description="Массив идентификаторов тегов, которые станут участниками", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_putStatus.py b/src/generator2/generator2_full/models/models_reqBod_putStatus.py deleted file mode 100644 index 0e19d8f..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_putStatus.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class Putstatus(BaseModel): - status: Optional[Status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost201.py b/src/generator2/generator2_full/models/models_response_createChatpost201.py deleted file mode 100644 index 289211b..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost201.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseCreatechatPost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createChatpost400.py b/src/generator2/generator2_full/models/models_response_createChatpost400.py deleted file mode 100644 index 3d5be37..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatechatPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost422.py b/src/generator2/generator2_full/models/models_response_createChatpost422.py deleted file mode 100644 index 9ee79aa..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatechatPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost201.py b/src/generator2/generator2_full/models/models_response_createMessagepost201.py deleted file mode 100644 index a7da269..0000000 --- a/src/generator2/generator2_full/models/models_response_createMessagepost201.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseCreatemessagePost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost400.py b/src/generator2/generator2_full/models/models_response_createMessagepost400.py deleted file mode 100644 index b484245..0000000 --- a/src/generator2/generator2_full/models/models_response_createMessagepost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatemessagePost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost201.py b/src/generator2/generator2_full/models/models_response_createTaskpost201.py deleted file mode 100644 index 749ca91..0000000 --- a/src/generator2/generator2_full/models/models_response_createTaskpost201.py +++ /dev/null @@ -1,66 +0,0 @@ -from enum import IntEnum, StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - value: Optional[str] = Field(None, description="Значение поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - - -class enum_kind(StrEnum): - call = "call" - meeting = "meeting" - reminder = "reminder" - event = "event" - email = "email" - - -class enum_priority(IntEnum): - priority_1 = 1 - priority_2 = 2 - priority_3 = 3 - - -class Data(BaseModel): - kind: enum_kind = Field(..., description="Тип напоминания") - content: str = Field(..., description="Описание напоминания") - due_at: str = Field( - ..., description="Срок выполнения напоминания (ISO-8601)", - ) - priority: Optional[enum_priority] = Field( - None, - description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", - ) - performer_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов пользователей", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="No docstring provided", - ) - id: Optional[int] = Field( - None, description="Идентификатор созданного напоминания", - ) - user_id: Optional[int] = Field( - None, description="Идентификатор пользователя-создателя", - ) - status: Optional[str] = Field(None, description="Статус напоминания") - created_at: Optional[str] = Field( - None, description="Дата и время создания", - ) - - -class ResponseCreatetaskPost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost400.py b/src/generator2/generator2_full/models/models_response_createTaskpost400.py deleted file mode 100644 index 7b83d43..0000000 --- a/src/generator2/generator2_full/models/models_response_createTaskpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatetaskPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost200.py b/src/generator2/generator2_full/models/models_response_createThreadpost200.py deleted file mode 100644 index 93e2199..0000000 --- a/src/generator2/generator2_full/models/models_response_createThreadpost200.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред.", - ) - message_chat_id: Optional[int] = Field( - None, description="Идентификатор чата сообщения.", - ) - updated_at: Optional[str] = Field( - None, - description="Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", - ) - - -class ResponseCreatethreadPost200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost400.py b/src/generator2/generator2_full/models/models_response_createThreadpost400.py deleted file mode 100644 index aab3648..0000000 --- a/src/generator2/generator2_full/models/models_response_createThreadpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatethreadPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py deleted file mode 100644 index c80757d..0000000 --- a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseDeletemessagereactionsDelete400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_editMessageput200.py b/src/generator2/generator2_full/models/models_response_editMessageput200.py deleted file mode 100644 index 2daa577..0000000 --- a/src/generator2/generator2_full/models/models_response_editMessageput200.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseEditmessagePut200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_editMessageput400.py b/src/generator2/generator2_full/models/models_response_editMessageput400.py deleted file mode 100644 index cb7e60d..0000000 --- a/src/generator2/generator2_full/models/models_response_editMessageput400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseEditmessagePut400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatget200.py b/src/generator2/generator2_full/models/models_response_getChatget200.py deleted file mode 100644 index 26c9d0a..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatget200.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseGetchatGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getChatget400.py b/src/generator2/generator2_full/models/models_response_getChatget400.py deleted file mode 100644 index 5cf12e6..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget200.py b/src/generator2/generator2_full/models/models_response_getChatsget200.py deleted file mode 100644 index 68c2eec..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget200.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseGetchatsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget400.py b/src/generator2/generator2_full/models/models_response_getChatsget400.py deleted file mode 100644 index 0893c6b..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget422.py b/src/generator2/generator2_full/models/models_response_getChatsget422.py deleted file mode 100644 index 89c7937..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatsGet422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py deleted file mode 100644 index 9c132b3..0000000 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py +++ /dev/null @@ -1,23 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Название поля") - name: Optional[str] = Field(None, description="Идентификатор поля") - data_type: Optional[enum_data_type] = Field(None, description="тип поля") - - -class ResponseGetcommonmethodsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py deleted file mode 100644 index f2ae8ba..0000000 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetcommonmethodsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py deleted file mode 100644 index a798652..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py +++ /dev/null @@ -1,90 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class User_status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - user_status: Optional[User_status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) - title: Optional[str] = Field(None, description="Должность") - created_at: Optional[str] = Field( - None, - description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - time_zone: Optional[str] = Field( - None, description="Часовой пояс пользователя", - ) - image_url: Optional[str] = Field( - None, description="Ссылка на скачивание аватарки", - ) - - -class ResponseGetemployeeGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py deleted file mode 100644 index a22237a..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetemployeeGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py deleted file mode 100644 index 6f24174..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py +++ /dev/null @@ -1,92 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class User_status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - user_status: Optional[User_status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) - title: Optional[str] = Field(None, description="Должность") - created_at: Optional[str] = Field( - None, - description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - time_zone: Optional[str] = Field( - None, description="Часовой пояс пользователя", - ) - image_url: Optional[str] = Field( - None, description="Ссылка на скачивание аватарки", - ) - - -class ResponseGetemployeesGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget200.py b/src/generator2/generator2_full/models/models_response_getListMessageget200.py deleted file mode 100644 index c187528..0000000 --- a/src/generator2/generator2_full/models/models_response_getListMessageget200.py +++ /dev/null @@ -1,106 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseGetlistmessageGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget400.py b/src/generator2/generator2_full/models/models_response_getListMessageget400.py deleted file mode 100644 index 9bc441d..0000000 --- a/src/generator2/generator2_full/models/models_response_getListMessageget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetlistmessageGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py deleted file mode 100644 index ce9da6a..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - user_id: Optional[int] = Field( - None, description="Идентификатор пользователя, оставившего реакцию.", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", - ) - code: Optional[str] = Field(None, description="Emoji символ реакции.") - - -class ResponseGetmessagereactionsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py deleted file mode 100644 index 369fcdf..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetmessagereactionsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageget200.py b/src/generator2/generator2_full/models/models_response_getMessageget200.py deleted file mode 100644 index 92d3d71..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageget200.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseGetmessageGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getMessageget400.py b/src/generator2/generator2_full/models/models_response_getMessageget400.py deleted file mode 100644 index 9c51172..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetmessageGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getStatusget200.py b/src/generator2/generator2_full/models/models_response_getStatusget200.py deleted file mode 100644 index 0d09a11..0000000 --- a/src/generator2/generator2_full/models/models_response_getStatusget200.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class ResponseGetstatusGet200(BaseModel): - data: Optional[Data] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget200.py b/src/generator2/generator2_full/models/models_response_getTagget200.py deleted file mode 100644 index ef7a650..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagget200.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор тега") - name: Optional[str] = Field(None, description="Название тега") - users_count: Optional[int] = Field( - None, description="Количество сотрудников, которые имеют этот тег", - ) - - -class ResponseGettagGet200(BaseModel): - data: Optional[Data] = Field( - None, - description="Для получения тега вам необходимо знать его id и указать его в URL запроса.", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget400.py b/src/generator2/generator2_full/models/models_response_getTagget400.py deleted file mode 100644 index a3b9fe0..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py deleted file mode 100644 index d835b3a..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py +++ /dev/null @@ -1,68 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - - -class ResponseGettagsemployeesGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py deleted file mode 100644 index a7c67de..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagsemployeesGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget200.py b/src/generator2/generator2_full/models/models_response_getTagsget200.py deleted file mode 100644 index a6f0b4b..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsget200.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор тега") - name: Optional[str] = Field(None, description="Название тега") - users_count: Optional[int] = Field( - None, description="Количество сотрудников, которые имеют этот тег", - ) - - -class ResponseGettagsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget400.py b/src/generator2/generator2_full/models/models_response_getTagsget400.py deleted file mode 100644 index 0015a61..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getUploadspost200.py b/src/generator2/generator2_full/models/models_response_getUploadspost200.py deleted file mode 100644 index 0d31122..0000000 --- a/src/generator2/generator2_full/models/models_response_getUploadspost200.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class ResponseGetuploadsPost200(BaseModel): - Content_Disposition: Optional[str] = Field( - None, - description="Используемый заголовок", - alilas="Content-Disposition", - ) - acl: Optional[str] = Field(None, description="Уровень безопасности") - policy: Optional[str] = Field( - None, description="Уникальный policy для загрузки файла", - ) - x_amz_credential: Optional[str] = Field( - None, - description="x-amz-credential для загрузки файла", - alilas="x-amz-credential", - ) - x_amz_algorithm: Optional[str] = Field( - None, description="Используемый алгоритм", alilas="x-amz-algorithm", - ) - x_amz_date: Optional[str] = Field( - None, - description="Уникальный x-amz-date для загрузки файла", - alilas="x-amz-date", - ) - x_amz_signature: Optional[str] = Field( - None, - description="Уникальная подпись для загрузки файла", - alilas="x-amz-signature", - ) - key: Optional[str] = Field( - None, description="Уникальный ключ для загрузки файла", - ) - direct_url: Optional[str] = Field( - None, description="Адрес для загрузки файла", - ) diff --git a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py deleted file mode 100644 index 3e430a1..0000000 --- a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseLeavechatDelete400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py deleted file mode 100644 index 5dd1dbd..0000000 --- a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmemberstochatsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py deleted file mode 100644 index bdf933f..0000000 --- a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmemberstochatsPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py deleted file mode 100644 index 0d305f2..0000000 --- a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmessagereactionsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py deleted file mode 100644 index e0385a7..0000000 --- a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePosttagstochatsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py deleted file mode 100644 index 8b157bf..0000000 --- a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePosttagstochatsPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput201.py b/src/generator2/generator2_full/models/models_response_putStatusput201.py deleted file mode 100644 index db4d1ca..0000000 --- a/src/generator2/generator2_full/models/models_response_putStatusput201.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class ResponsePutstatusPut201(BaseModel): - data: Optional[Data] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput400.py b/src/generator2/generator2_full/models/models_response_putStatusput400.py deleted file mode 100644 index 74a54e1..0000000 --- a/src/generator2/generator2_full/models/models_response_putStatusput400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePutstatusPut400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py index 04e6a41..e69de29 100644 --- a/src/generator2/generator2_full/request_methods.py +++ b/src/generator2/generator2_full/request_methods.py @@ -1,608 +0,0 @@ -from .models.models_reqBod_createChat import Createchat -from .models.models_reqBod_createMessage import Createmessage -from .models.models_reqBod_createTask import Createtask -from .models.models_reqBod_editMessage import Editmessage -from .models.models_reqBod_getDirectUrl import Getdirecturl -from .models.models_reqBod_postMembersToChats import Postmemberstochats -from .models.models_reqBod_postMessageReactions import Postmessagereactions -from .models.models_reqBod_postTagsToChats import Posttagstochats -from .models.models_reqBod_putStatus import Putstatus -from .models.models_response_createChatpost201 import ResponseCreatechatPost201 -from .models.models_response_createChatpost422 import ResponseCreatechatPost422 -from .models.models_response_createMessagepost201 import ( - ResponseCreatemessagePost201, -) -from .models.models_response_createMessagepost400 import ( - ResponseCreatemessagePost400, -) -from .models.models_response_createTaskpost201 import ResponseCreatetaskPost201 -from .models.models_response_createTaskpost400 import ResponseCreatetaskPost400 -from .models.models_response_createThreadpost200 import ( - ResponseCreatethreadPost200, -) -from .models.models_response_createThreadpost400 import ( - ResponseCreatethreadPost400, -) -from .models.models_response_deleteMessageReactionsdelete400 import ( - ResponseDeletemessagereactionsDelete400, -) -from .models.models_response_editMessageput200 import ResponseEditmessagePut200 -from .models.models_response_editMessageput400 import ResponseEditmessagePut400 -from .models.models_response_getChatget200 import ResponseGetchatGet200 -from .models.models_response_getChatget400 import ResponseGetchatGet400 -from .models.models_response_getChatsget200 import ResponseGetchatsGet200 -from .models.models_response_getChatsget422 import ResponseGetchatsGet422 -from .models.models_response_getCommonMethodsget200 import ( - ResponseGetcommonmethodsGet200, -) -from .models.models_response_getCommonMethodsget400 import ( - ResponseGetcommonmethodsGet400, -) -from .models.models_response_getEmployeeget200 import ResponseGetemployeeGet200 -from .models.models_response_getEmployeeget400 import ResponseGetemployeeGet400 -from .models.models_response_getEmployeesget200 import ( - ResponseGetemployeesGet200, -) -from .models.models_response_getListMessageget200 import ( - ResponseGetlistmessageGet200, -) -from .models.models_response_getListMessageget400 import ( - ResponseGetlistmessageGet400, -) -from .models.models_response_getMessageReactionsget200 import ( - ResponseGetmessagereactionsGet200, -) -from .models.models_response_getMessageReactionsget400 import ( - ResponseGetmessagereactionsGet400, -) -from .models.models_response_getMessageget200 import ResponseGetmessageGet200 -from .models.models_response_getMessageget400 import ResponseGetmessageGet400 -from .models.models_response_getStatusget200 import ResponseGetstatusGet200 -from .models.models_response_getTagget200 import ResponseGettagGet200 -from .models.models_response_getTagget400 import ResponseGettagGet400 -from .models.models_response_getTagsEmployeesget200 import ( - ResponseGettagsemployeesGet200, -) -from .models.models_response_getTagsEmployeesget400 import ( - ResponseGettagsemployeesGet400, -) -from .models.models_response_getTagsget200 import ResponseGettagsGet200 -from .models.models_response_getTagsget400 import ResponseGettagsGet400 -from .models.models_response_getUploadspost200 import ResponseGetuploadsPost200 -from .models.models_response_leaveChatdelete400 import ( - ResponseLeavechatDelete400, -) -from .models.models_response_postMembersToChatspost422 import ( - ResponsePostmemberstochatsPost422, -) -from .models.models_response_postMessageReactionspost400 import ( - ResponsePostmessagereactionsPost400, -) -from .models.models_response_postTagsToChatspost422 import ( - ResponsePosttagstochatsPost422, -) -from .models.models_response_putStatusput201 import ResponsePutstatusPut201 -from .models.models_response_putStatusput400 import ResponsePutstatusPut400 - - -async def get_common_methods( - self, entity_type: str = None, -) -> ResponseGetcommonmethodsGet200: - """получение списка актульных полей сущности - - Метод для получения актуального списка дополнительных полей участников и - напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в - URL (например, /custom_properties?entity_type=User) - """ - client = await self.get_client() - async with client: - url = "/custom_properties" - query_params = self.filter_query_params(entity_type=entity_type) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetcommonmethodsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetcommonmethodsGet400.model_validate_json( - response.text, - ) - return None - - -async def get_uploads(self) -> ResponseGetuploadsPost200: - """получения подписи и ключа для загрузки файла - - Данный метод необходимо использовать для загрузки каждого файла. Данный метод - позволяет получить уникальный набор параметров для загрузки файла. Параметры - запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/uploads" - response = await client.post(url) - if response.is_success: - return ResponseGetuploadsPost200.model_validate_json(response.text) - return None - - -async def get_direct_url(self, data: Getdirecturl): - """(полученный в ответе на запрос /uploads) загрузка файла - - Данный метод не требует авторизации. Получив все параметры, вам необходимо - сделать POST запрос в формате multipart/form-data на адрес, который был указан - в поле direct_url, отправив полученные параметры и сам файл. - """ - client = await self.get_client() - async with client: - url = "/direct_url" - response = await client.post(url, json=data.model_dump()) - return - - -async def get_employees( - self, per: int = None, page: int = None, query: str = None, -) -> ResponseGetemployeesGet200: - """получение актуального списка всех сотрудников компании - - Метод для получения актуального списка сотрудников вашей компании. Тело запроса - отсутствует, параметры передаются в URL (например, - /users?per=50&page=2&query=example.com) - """ - client = await self.get_client() - async with client: - url = "/users" - query_params = self.filter_query_params( - per=per, page=page, query=query, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetemployeesGet200.model_validate_json( - response.text, - ) - return None - - -async def get_employee(self, id: int) -> ResponseGetemployeeGet200: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. Для получения сотрудника вам - необходимо знать его id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = self.format_url("/users/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetemployeeGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetemployeeGet400.model_validate_json(response.text) - return None - - -async def get_status(self) -> ResponseGetstatusGet200: - """получение информации о своем статусе - - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.get(url) - if response.is_success: - return ResponseGetstatusGet200.model_validate_json(response.text) - return None - - -async def put_status(self, data: Putstatus) -> ResponsePutstatusPut201: - """новый статус - - Метод для установки себе нового статуса. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.put(url, json=data.model_dump()) - if response.is_success: - return ResponsePutstatusPut201.model_validate_json(response.text) - if response.is_client_error: - return ResponsePutstatusPut400.model_validate_json(response.text) - return None - - -async def del_status(self): - """удаление своего статуса - - Метод для удаления своего статуса. Параметры запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.delete(url) - return - - -async def get_tag(self, id: int) -> ResponseGettagGet200: - """получение информации о теге - - Метод для получения информации о теге. Названия тегов являются уникальными в - компании. Для получения тега вам необходимо знать его id и указать его в URL - запроса. Параметры запроса отсутствуют - """ - client = await self.get_client() - async with client: - url = self.format_url("/group_tags/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGettagGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGettagGet400.model_validate_json(response.text) - return None - - -async def get_tags( - self, per: int = None, page: int = None, -) -> ResponseGettagsGet200: - """получение актуального списка тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. Названия тегов - являются уникальными в компании. Тело запроса отсутствует, параметры передаются - в URL (например, /group_tags?per=10&page=2) - """ - client = await self.get_client() - async with client: - url = "/group_tags" - query_params = self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGettagsGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGettagsGet400.model_validate_json(response.text) - return None - - -async def get_tags_employees( - self, id: int, per: int = None, page: int = None, -) -> ResponseGettagsemployeesGet200: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. Идентификатор тега, - список сотрудников которого необходимо получить, и другие параметры передаются - в URL (например, /group_tags/877650/users?per=3&page=2) - """ - client = await self.get_client() - async with client: - url = self.format_url("/group_tags/{id}/users", {"id": id}) - query_params = self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGettagsemployeesGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGettagsemployeesGet400.model_validate_json( - response.text, - ) - return None - - -async def get_chats( - self, - sort_field: str = "id", - sort: str = "desc", - per: int = None, - page: int = None, - availability: str = None, - last_message_at_after: str = None, - last_message_at_before: str = None, -) -> ResponseGetchatsGet200: - """получение списка бесед и каналов - - Метод для получения списка бесед и каналов по заданным параметрам. Тело - запроса отсутствует, параметры передаются в URL (например, - /chats?per=2&sort[id]=desc) - """ - client = await self.get_client() - async with client: - url = "/chats" - query_params = self.filter_query_params( - sort_field=sort_field, - sort=sort, - per=per, - page=page, - availability=availability, - last_message_at_after=last_message_at_after, - last_message_at_before=last_message_at_before, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetchatsGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetchatsGet422.model_validate_json(response.text) - return None - - -async def create_chat(self, data: Createchat) -> ResponseCreatechatPost201: - """создание новой беседы или канала - - Метод для создания новой беседы или нового канала. При создании беседы или - канала вы автоматически становитесь участником. - """ - client = await self.get_client() - async with client: - url = "/chats" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatechatPost201.model_validate_json(response.text) - if response.is_client_error: - return ResponseCreatechatPost422.model_validate_json(response.text) - return None - - -async def get_chat(self, id: int) -> ResponseGetchatGet200: - """получение информации о беседе или канале - - Получения информации о беседе или канале. Для получения беседы или канала вам - необходимо знать её id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetchatGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetchatGet400.model_validate_json(response.text) - return None - - -async def post_members_to_chats(self, data: Postmemberstochats, id: int): - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}/members", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePostmemberstochatsPost422.model_validate_json( - response.text, - ) - return None - - -async def post_tags_to_chats(self, data: Posttagstochats, id: int): - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}/group_tags", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePosttagstochatsPost422.model_validate_json( - response.text, - ) - return None - - -async def leave_chat(self, id: int): - """выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. Параметры запроса - отсутствуют/ - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}/leave", {"id": id}) - response = await client.delete(url) - if response.is_client_error: - return ResponseLeavechatDelete400.model_validate_json( - response.text, - ) - return None - - -async def create_thread(self, id: int) -> ResponseCreatethreadPost200: - """создание нового треда - - Метод для создания нового треда к сообщению. Если у сообщения уже был создан - тред, то в ответе вернётся информация об уже созданном ранее треде. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/thread", {"id": id}) - response = await client.post(url) - if response.is_success: - return ResponseCreatethreadPost200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatethreadPost400.model_validate_json( - response.text, - ) - return None - - -async def get_list_message( - self, chat_id: int = None, per: int = None, page: int = None, -) -> ResponseGetlistmessageGet200: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в - порядке убывания даты отправки (то есть, сначала будут идти последние сообщения - чата). Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, - /messages?chat_id=198&per=3) - """ - client = await self.get_client() - async with client: - url = "/messages" - query_params = self.filter_query_params( - chat_id=chat_id, per=per, page=page, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetlistmessageGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetlistmessageGet400.model_validate_json( - response.text, - ) - return None - - -async def create_message( - self, data: Createmessage, -) -> ResponseCreatemessagePost201: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, личного сообщения пользователю - или комментария в тред. При использовании entity_type: "discussion" (или - просто без указания entity_type) допускается отправка любого chat_id в поле - entity_id. То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его - идентификатору или личное сообщение по идентификатору пользователя. Для - отправки личного сообщения пользователю создавать чат не требуется. Достаточно - указать entity_type: "user" и идентификатор пользователя. Чат будет создан - автоматически, если между вами ещё не было переписки. Между двумя - пользователями может быть только один личный чат. - """ - client = await self.get_client() - async with client: - url = "/messages" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatemessagePost201.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatemessagePost400.model_validate_json( - response.text, - ) - return None - - -async def get_message(self, id: int) -> ResponseGetmessageGet200: - """получение информации о сообщении - - Метод для получения информации о сообщении. Для получения сообщения вам - необходимо знать его id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetmessageGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetmessageGet400.model_validate_json(response.text) - return None - - -async def edit_message( - self, data: Editmessage, id: int, -) -> ResponseEditmessagePut200: - """редактирование сообщения по указанному идентификатору - - Метод для редактирования сообщения или комментария. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}", {"id": id}) - response = await client.put(url, json=data.model_dump()) - if response.is_success: - return ResponseEditmessagePut200.model_validate_json(response.text) - if response.is_client_error: - return ResponseEditmessagePut400.model_validate_json(response.text) - return None - - -async def get_message_reactions( - self, id: int, per: int = None, page: int = None, -) -> ResponseGetmessagereactionsGet200: - """получение актуального списка реакций - - Метод для получения актуального списка реакций на сообщение. Идентификатор - сообщения, список реакций на которое необходимо получить, передается в URL - (например, /messages/7231942/reactions). Количество возвращаемых сущностей и - страница выборки указываются в теле запроса - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/reactions", {"id": id}) - query_params = self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetmessagereactionsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetmessagereactionsGet400.model_validate_json( - response.text, - ) - return None - - -async def post_message_reactions(self, data: Postmessagereactions, id: int): - """добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый - пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - Сообщение может иметь - не более 1000 реакций. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/reactions", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePostmessagereactionsPost400.model_validate_json( - response.text, - ) - return None - - -async def delete_message_reactions(self, id: int, code: str = None): - """удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, - которые были поставлены авторизованным пользователем. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/reactions", {"id": id}) - query_params = self.filter_query_params(code=code) - response = await client.delete(url, params=query_params) - if response.is_client_error: - return ResponseDeletemessagereactionsDelete400.model_validate_json( - response.text, - ) - return None - - -async def create_task(self, data: Createtask) -> ResponseCreatetaskPost201: - """создание нового напоминания - - Метод для создания нового напоминания. При создании напоминания обязательным - условием является указания типа напоминания: звонок, встреча, простое - напоминание, событие или письмо. При этом не требуется дополнительное описание - - вы просто создадите напоминание с соответствующим текстом. Если вы укажите - описание напоминания - то именно оно и станет текстом напоминания. У - напоминания должны быть ответственные, если их не указывать - ответственным - назначаетесь вы. - """ - client = await self.get_client() - async with client: - url = "/tasks" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatetaskPost201.model_validate_json(response.text) - if response.is_client_error: - return ResponseCreatetaskPost400.model_validate_json(response.text) - return None diff --git a/src/repository/pachca_generator1-1.0.0-py3-none-any.whl b/src/repository/pachca_generator1-1.0.0-py3-none-any.whl deleted file mode 100644 index 971a2c75943261b3a8f6ceff30036dd34c1f3b1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124663 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 G22F?Nk9x`v}uM=b3ltS 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 Gzy1eUmz{S2 diff --git a/src/repository/pachca_generator2-1.0.0-py3-none-any.whl b/src/repository/pachca_generator2-1.0.0-py3-none-any.whl deleted file mode 100644 index 1169b43ea03fd30352207a11510f6bbc45abadf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177088 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�CP$1H0=GwdpE`C2BFrI!;Uc8Q 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 z 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 Date: Sun, 12 Jan 2025 18:52:14 +0300 Subject: [PATCH 239/296] finish --- src/generator1/pachca.bak | 184 -------------------------------------- src/generator1/pachca.py | 119 ++++++++++++------------ 2 files changed, 55 insertions(+), 248 deletions(-) delete mode 100644 src/generator1/pachca.bak diff --git a/src/generator1/pachca.bak b/src/generator1/pachca.bak deleted file mode 100644 index 17f5d7f..0000000 --- a/src/generator1/pachca.bak +++ /dev/null @@ -1,184 +0,0 @@ -import asyncio -import datetime -import os - -from dotenv import load_dotenv -from logger_setup import setup_logging -from pachca_api_open_api_3_0_client.client import Pachca -from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, - EditMessageBody, - EditMessages, - QueryStatusStatus, -) -from pachca_api_open_api_3_0_client.models.base_chat import BaseChat -from pachca_api_open_api_3_0_client.models.chat import Chat -from pachca_api_open_api_3_0_client.models.code_reaction import ( - CodeReaction, -) -from pachca_api_open_api_3_0_client.models.create_chat_body import ( - CreateChatBody, -) -from pachca_api_open_api_3_0_client.models.create_message_body import ( - CreateMessageBody, -) -from pachca_api_open_api_3_0_client.models.create_messages import ( - CreateMessages, -) -from pachca_api_open_api_3_0_client.models.create_task_body import ( - CreateTaskBody, -) -from pachca_api_open_api_3_0_client.models.put_status_body import ( - PutStatusBody, -) - -load_dotenv() -pachca = Pachca(os.getenv('TOKEN')) - -logger = setup_logging( - 'test_requests_logging', - 'pachca_testresults.log' -) - - -async def main() -> None: - """ Функция теста эндпоинтов """ - - query_chat = BaseChat(name='test500_2') - chat_body = CreateChatBody(chat=query_chat) - - chat_create = asyncio.create_task( - pachca.createChat(body=chat_body)) - - chat_response = await chat_create - - # запрос на получение списка бесед и каналов - - create_task = await asyncio.create_task(pachca.getChats()) - - # запрос на получение информации о беседе - - getChat = await asyncio.create_task( - pachca.getChat(id=chat_response.data.id) - ) - - # подготовка запроса на создание сообщения в созданную беседу --> - - create_message = CreateMessages( - - entity_id=chat_response.data.id, content='Super puper') - - message_body = CreateMessageBody(message=create_message) - - # запрос на создание сообщения в созданную беседу - - message_create = asyncio.create_task( - pachca.createMessage(body=message_body)) - - message_response = await message_create - - # создание треда к созданному сообщению - - thread_create = asyncio.create_task( - pachca.createThread(id=message_response.data.id) - ) - - # запрос на получение списка сообщений - - getListMessage = await asyncio.create_task( - - pachca.getListMessage(chat_id=chat_response.data.id)) - - # запрос на получение сообщения - - getMessage = await asyncio.create_task( - - pachca.getMessage(id=message_response.data.id)) - - # подготовка запроса на редактирование сообщения --> - - edit_meassage = EditMessages(content='NOT SUPER PUPER') - - edit_message_body = EditMessageBody(message=edit_meassage) - - # запрос на редактирование сообщения - - editMessage = await asyncio.create_task( - pachca.editMessage( - id=message_response.data.id, body=edit_message_body) - ) - - # запрос на удаление статуса - - print(await asyncio.create_task(pachca.delStatus())) - - # запрос на получение тегов сотрудников - - print(await asyncio.create_task(pachca.getTags())) - - # запрос на получение списка актуальных полей сущности - - print(await asyncio.create_task( - - pachca.getCommonMethods(entity_type='User')) - - ) - post_reactions = CodeReaction(code='😭') - postMessageReactions = await pachca.postMessageReactions( - id=message_response.data.id, body=post_reactions - ) - - getMessageReactions = await pachca.getMessageReactions(id=message_response.data.id) - - deleteMessageReactions = await pachca.deleteMessageReactions(id=message_response.data.id, code='😭') - - # запрос на создание напоминания - - create_body_task = CreateTaskBodyTask( - kind='call', - content='Звонок другу', - due_at=datetime.datetime.now(), - ) - - body_task = CreateTaskBody(task=create_body_task) - # <-- - - createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) - - users_response = await asyncio.create_task(pachca.getEmployees()) - - getEmployee = await asyncio.create_task(pachca.getEmployee(id=users_response.data[0].id)) - - # запрос получения подписи и ключа для загрузки файла - - logger.debug(await pachca.getUploads()) - - for task in ( - chat_response, - create_task, - getChat, - message_response, - thread_create, - getListMessage, - getMessage, - editMessage, - create_task, - postMessageReactions, - getMessageReactions, - deleteMessageReactions, - createtaskbody, - users_response, - getEmployee, - ): - - result = task - - logger.debug( - f"{task}: data={result} \n" - "**", - ) - logger.debug('Tests ended '+'*'*100) - - -if __name__ == '__main__': - asyncio.run(main()) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index faf7320..735ad1e 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -18,16 +18,13 @@ from pachca_api_open_api_3_0_client.models.create_task_body import ( CreateTaskBody, ) - from pachca_api_open_api_3_0_client.models import ( CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody ) - from pachca_api_open_api_3_0_client.models.base_chat import BaseChat from pachca_api_open_api_3_0_client.models.code_reaction import ( CodeReaction, ) - from pachca_api_open_api_3_0_client.models.put_status_body import ( PutStatusBody, ) @@ -35,6 +32,10 @@ load_dotenv() pachca = Pachca(os.getenv('TOKEN')) +logger = setup_logging( + 'test_requests_logging', + 'pachca_testresults.log' +) async def main() -> None: """ Функция теста эндпоинтов """ @@ -47,19 +48,14 @@ async def main() -> None: chat_create = asyncio.create_task( pachca.createChat(body=chat_body)) chat_response = await chat_create - print(chat_response) - print('*' * 60) # запрос на получение списка бесед и каналов - print(await asyncio.create_task(pachca.getChats())) - print('*' * 60) + create_task = await asyncio.create_task(pachca.getChats()) # запрос на получение информации о беседе - print(await asyncio.create_task( - pachca.getChat(id=chat_response.data.id)) + getChat = await asyncio.create_task( + pachca.getChat(id=chat_response.data.id) ) - print('*' * 60) - # подготовка запроса на создание сообщения в созданную беседу --> create_message = CreateMessages( entity_id=chat_response.data.id, content='Super puper') @@ -69,67 +65,44 @@ async def main() -> None: message_create = asyncio.create_task( pachca.createMessage(body=message_body)) message_response = await message_create - print(message_response) - print('*' * 60) - # создание треда к созданному сообщению thread_create = asyncio.create_task( pachca.createThread(id=message_response.data.id) ) - print(await thread_create) - print('*' * 60) - # запрос на получение списка сообщений - print(await asyncio.create_task( + getListMessage = await asyncio.create_task( pachca.getListMessage(chat_id=chat_response.data.id)) - ) - print('*' * 60) # запрос на получение сообщения - print(await asyncio.create_task( + getMessage = await asyncio.create_task( pachca.getMessage(id=message_response.data.id)) - ) - print('*' * 60) - # подготовка запроса на редактирование сообщения --> edit_meassage = EditMessages(content='NOT SUPER PUPER') edit_message_body = EditMessageBody(message=edit_meassage) # <-- # запрос на редактирование сообщения - print(await asyncio.create_task( + editMessage = await asyncio.create_task( pachca.editMessage( id=message_response.data.id, body=edit_message_body) ) - ) - print('*' * 60) # подготовка запроса на добавление реакции к сообщению --> post_reactions = CodeReaction(code='😭') # <-- # запрос на добавление реакции к сообщению - print(await asyncio.create_task( - pachca.postMessageReactions( - id=message_response.data.id, body=post_reactions) - ) + postMessageReactions = await pachca.postMessageReactions( + id=message_response.data.id, body=post_reactions ) - print('*' * 60) # подготовка запроса на получение списка реакций к сообщению --> # <-- # запрос на получение списка реакций - print(await asyncio.create_task( - pachca.getMessageReactions(id=message_response.data.id)) - ) - print('*' * 60) + getMessageReactions = await pachca.getMessageReactions(id=message_response.data.id) # запрос на удаление реакции - print(await asyncio.create_task( - pachca.deleteMessageReactions(id=message_response.data.id, code='😭') - ) - ) - print('*' * 60) + deleteMessageReactions = await pachca.deleteMessageReactions(id=message_response.data.id, code='😭') # подготовка запроса на создание напоминания --> create_body_task = CreateTaskBodyTask( @@ -140,19 +113,13 @@ async def main() -> None: body_task = CreateTaskBody(task=create_body_task) # <-- # запрос на создание напоминания - print(await asyncio.create_task(pachca.createTask(body=body_task))) - print('*' * 60) + createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) # запрос на получения списка пользователей users_response = await asyncio.create_task(pachca.getEmployees()) - print(users_response) - print('*' * 60) # запрос на получение информации о пользователе - print(await asyncio.create_task( - pachca.getEmployee(id=users_response.data[0].id)) - ) - print('*' * 60) + getEmployee = await asyncio.create_task(pachca.getEmployee(id=users_response.data[0].id)) # подготовка запроса на добавление статуса --> query_status = QueryStatusStatus( @@ -162,32 +129,56 @@ async def main() -> None: ) # <-- # запрос на добавление статуса - print(await asyncio.create_task(pachca.putStatus(body=query_status))) - print('*' * 60) + putStatus = await asyncio.create_task(pachca.putStatus(body=query_status)) # запрос на получение информации о своем статусе - print(await asyncio.create_task(pachca.getStatus())) - print('*' * 60) - - + getStatus = await asyncio.create_task(pachca.getStatus()) # запрос на удаление статуса - print(await asyncio.create_task(pachca.delStatus())) - print('*' * 60) + delStatus = await asyncio.create_task(pachca.delStatus()) # запрос на получение тегов сотрудников - print(await asyncio.create_task(pachca.getTags())) - print('*' * 60) + getTags = await asyncio.create_task(pachca.getTags()) # запрос на получение списка актуальных полей сущности - print(await asyncio.create_task( + getCommonMethods = await asyncio.create_task( pachca.getCommonMethods(entity_type='User')) - ) - print('*' * 60) # запрос получения подписи и ключа для загрузки файла - print(await asyncio.create_task(pachca.getUploads())) - print('*' * 60) + getUploads = await asyncio.create_task(pachca.getUploads()) + + logger.debug(await pachca.getUploads()) + + for task in ( + chat_response, + create_task, + getChat, + message_response, + thread_create, + getListMessage, + getMessage, + editMessage, + create_task, + postMessageReactions, + getMessageReactions, + deleteMessageReactions, + createtaskbody, + users_response, + getEmployee, + putStatus, + getStatus, + delStatus, + getTags, + getCommonMethods, + getUploads, + ): + + result = task + logger.debug( + f"{task}: data={result} \n" + "**", + ) + logger.debug('Tests ended '+'*'*100) if __name__ == '__main__': asyncio.run(main()) From 29f5b53f2327232dbdedfc5f00169047c4161987 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 12 Jan 2025 18:52:38 +0300 Subject: [PATCH 240/296] fixed project #2 --- src/builder/setup_generator1.py | 6 +++--- src/builder/setup_generator2.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/builder/setup_generator1.py b/src/builder/setup_generator1.py index a3fba45..33d153a 100644 --- a/src/builder/setup_generator1.py +++ b/src/builder/setup_generator1.py @@ -1,11 +1,11 @@ -from setuptools import setup, find_packages - import json import os from pathlib import Path +from setuptools import find_packages, setup + this_directory = Path(__file__).parent -long_description = (this_directory / "../../README.md").read_text() +long_description = (this_directory / "../../README.md").read_text(encoding='utf-8') def read_pipenv_dependencies(fname): diff --git a/src/builder/setup_generator2.py b/src/builder/setup_generator2.py index 5b31ce6..5d7532b 100644 --- a/src/builder/setup_generator2.py +++ b/src/builder/setup_generator2.py @@ -1,11 +1,11 @@ -from setuptools import setup, find_packages - import json import os from pathlib import Path +from setuptools import find_packages, setup + this_directory = Path(__file__).parent -long_description = (this_directory / "../../README.md").read_text() +long_description = (this_directory / "../../README.md").read_text(encoding='utf-8') def read_pipenv_dependencies(fname): From 366c30173ea6322165141957a8d117e962d38a3b Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 13 Jan 2025 02:08:49 +0300 Subject: [PATCH 241/296] fixed project #3 --- .../models/models_reqBod_createChat.py | 28 +++++ .../models/models_reqBod_createMessage.py | 66 +++++++++++ .../models/models_reqBod_createTask.py | 45 ++++++++ .../models/models_reqBod_editMessage.py | 46 ++++++++ .../models/models_reqBod_getDirectUrl.py | 37 ++++++ .../models_reqBod_postMembersToChats.py | 14 +++ .../models_reqBod_postMessageReactions.py | 7 ++ .../models/models_reqBod_postTagsToChats.py | 10 ++ .../models/models_reqBod_putStatus.py | 19 ++++ .../models_response_createChatpost201.py | 43 +++++++ .../models_response_createChatpost400.py | 30 +++++ .../models_response_createChatpost422.py | 30 +++++ .../models_response_createMessagepost201.py | 104 +++++++++++++++++ .../models_response_createMessagepost400.py | 30 +++++ .../models_response_createTaskpost201.py | 66 +++++++++++ .../models_response_createTaskpost400.py | 30 +++++ .../models_response_createThreadpost200.py | 23 ++++ .../models_response_createThreadpost400.py | 30 +++++ ...esponse_deleteMessageReactionsdelete400.py | 30 +++++ .../models_response_editMessageput200.py | 104 +++++++++++++++++ .../models_response_editMessageput400.py | 30 +++++ .../models/models_response_getChatget200.py | 43 +++++++ .../models/models_response_getChatget400.py | 30 +++++ .../models/models_response_getChatsget200.py | 45 ++++++++ .../models/models_response_getChatsget400.py | 30 +++++ .../models/models_response_getChatsget422.py | 30 +++++ .../models_response_getCommonMethodsget200.py | 23 ++++ .../models_response_getCommonMethodsget400.py | 30 +++++ .../models_response_getEmployeeget200.py | 90 +++++++++++++++ .../models_response_getEmployeeget400.py | 30 +++++ .../models_response_getEmployeesget200.py | 92 +++++++++++++++ .../models_response_getListMessageget200.py | 106 ++++++++++++++++++ .../models_response_getListMessageget400.py | 30 +++++ ...dels_response_getMessageReactionsget200.py | 20 ++++ ...dels_response_getMessageReactionsget400.py | 30 +++++ .../models_response_getMessageget200.py | 104 +++++++++++++++++ .../models_response_getMessageget400.py | 30 +++++ .../models/models_response_getStatusget200.py | 19 ++++ .../models/models_response_getTagget200.py | 18 +++ .../models/models_response_getTagget400.py | 30 +++++ .../models_response_getTagsEmployeesget200.py | 68 +++++++++++ .../models_response_getTagsEmployeesget400.py | 30 +++++ .../models/models_response_getTagsget200.py | 17 +++ .../models/models_response_getTagsget400.py | 30 +++++ .../models_response_getUploadspost200.py | 39 +++++++ .../models_response_leaveChatdelete400.py | 30 +++++ ...dels_response_postMembersToChatspost400.py | 30 +++++ ...dels_response_postMembersToChatspost422.py | 30 +++++ ...ls_response_postMessageReactionspost400.py | 30 +++++ .../models_response_postTagsToChatspost400.py | 30 +++++ .../models_response_postTagsToChatspost422.py | 30 +++++ .../models/models_response_putStatusput201.py | 19 ++++ .../models/models_response_putStatusput400.py | 30 +++++ .../pachca_generator1-1.0.0-py3-none-any.whl | Bin 0 -> 128944 bytes .../pachca_generator2-1.0.0-py3-none-any.whl | Bin 0 -> 137640 bytes 55 files changed, 2065 insertions(+) create mode 100644 src/generator2/generator2_full/models/models_reqBod_createChat.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_createMessage.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_createTask.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_editMessage.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_putStatus.py create mode 100644 src/generator2/generator2_full/models/models_response_createChatpost201.py create mode 100644 src/generator2/generator2_full/models/models_response_createChatpost400.py create mode 100644 src/generator2/generator2_full/models/models_response_createChatpost422.py create mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost201.py create mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost400.py create mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost201.py create mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost400.py create mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost200.py create mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost400.py create mode 100644 src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py create mode 100644 src/generator2/generator2_full/models/models_response_editMessageput200.py create mode 100644 src/generator2/generator2_full/models/models_response_editMessageput400.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatsget422.py create mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getEmployeesget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getStatusget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getUploadspost200.py create mode 100644 src/generator2/generator2_full/models/models_response_leaveChatdelete400.py create mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py create mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py create mode 100644 src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py create mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py create mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py create mode 100644 src/generator2/generator2_full/models/models_response_putStatusput201.py create mode 100644 src/generator2/generator2_full/models/models_response_putStatusput400.py create mode 100644 src/repository/pachca_generator1-1.0.0-py3-none-any.whl create mode 100644 src/repository/pachca_generator2-1.0.0-py3-none-any.whl diff --git a/src/generator2/generator2_full/models/models_reqBod_createChat.py b/src/generator2/generator2_full/models/models_reqBod_createChat.py new file mode 100644 index 0000000..089e9c2 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_createChat.py @@ -0,0 +1,28 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Chat(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + + +class Createchat(BaseModel): + chat: Optional[Chat] = Field( + None, + description="Собранный объект параметров создаваемой беседы или канала", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createMessage.py b/src/generator2/generator2_full/models/models_reqBod_createMessage.py new file mode 100644 index 0000000..a6280ed --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_createMessage.py @@ -0,0 +1,66 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + size: int = Field( + ..., description="Размер файла в байтах, отображаемый пользователю", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Message(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + skip_invite_mentions: Optional[bool] = Field( + None, description="No docstring provided", + ) + link_preview: Optional[bool] = Field( + None, description="No docstring provided", + ) + + +class Createmessage(BaseModel): + message: Optional[Message] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createTask.py b/src/generator2/generator2_full/models/models_reqBod_createTask.py new file mode 100644 index 0000000..ce503e3 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_createTask.py @@ -0,0 +1,45 @@ +from enum import IntEnum, StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + value: Optional[str] = Field(None, description="Значение поля") + + +class enum_kind(StrEnum): + call = "call" + meeting = "meeting" + reminder = "reminder" + event = "event" + email = "email" + + +class enum_priority(IntEnum): + priority_1 = 1 + priority_2 = 2 + priority_3 = 3 + + +class Task(BaseModel): + kind: enum_kind = Field(..., description="Тип напоминания") + content: str = Field(..., description="Описание напоминания") + due_at: str = Field( + ..., description="Срок выполнения напоминания (ISO-8601)", + ) + priority: Optional[enum_priority] = Field( + None, + description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", + ) + performer_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов пользователей", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="No docstring provided", + ) + + +class Createtask(BaseModel): + task: Optional[Task] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_reqBod_editMessage.py b/src/generator2/generator2_full/models/models_reqBod_editMessage.py new file mode 100644 index 0000000..8db9faf --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_editMessage.py @@ -0,0 +1,46 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + size: int = Field( + ..., description="Размер файла в байтах, отображаемый пользователю", + ) + + +class Message(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + + +class Editmessage(BaseModel): + message: Optional[Message] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py new file mode 100644 index 0000000..a4f35e7 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py @@ -0,0 +1,37 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Getdirecturl(BaseModel): + Content_Disposition: Optional[str] = Field( + None, + description="Используемый заголовок", + alilas="Content-Disposition", + ) + acl: Optional[str] = Field(None, description="Уровень безопасности") + policy: Optional[str] = Field( + None, description="Уникальный policy для загрузки файла", + ) + x_amz_credential: Optional[str] = Field( + None, + description="x-amz-credential для загрузки файла", + alilas="x-amz-credential", + ) + x_amz_algorithm: Optional[str] = Field( + None, description="Используемый алгоритм", alilas="x-amz-algorithm", + ) + x_amz_date: Optional[str] = Field( + None, + description="Уникальный x-amz-date для загрузки файла", + alilas="x-amz-date", + ) + x_amz_signature: Optional[str] = Field( + None, + description="Уникальная подпись для загрузки файла", + alilas="x-amz-signature", + ) + key: Optional[str] = Field( + None, description="Уникальный ключ для загрузки файла", + ) + file: Optional[str] = Field(None, description="Адрес для загрузки файла") diff --git a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py new file mode 100644 index 0000000..59b7182 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py @@ -0,0 +1,14 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Postmemberstochats(BaseModel): + member_ids: List[int] = Field( + ..., + description="Массив идентификаторов пользователей, которые станут участниками", + ) + silent: Optional[bool] = Field( + None, + description="Не создавать в чате системное сообщение о добавлении участника", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py new file mode 100644 index 0000000..ba69294 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py @@ -0,0 +1,7 @@ +from pydantic import BaseModel, Field + + +class Postmessagereactions(BaseModel): + code: str = Field( + ..., description="Emoji в строковом формате для добавления реакции.", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py new file mode 100644 index 0000000..f935dd3 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py @@ -0,0 +1,10 @@ +from typing import List + +from pydantic import BaseModel, Field + + +class Posttagstochats(BaseModel): + group_tag_ids: List[int] = Field( + ..., + description="Массив идентификаторов тегов, которые станут участниками", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_putStatus.py b/src/generator2/generator2_full/models/models_reqBod_putStatus.py new file mode 100644 index 0000000..0e19d8f --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_putStatus.py @@ -0,0 +1,19 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Status(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class Putstatus(BaseModel): + status: Optional[Status] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost201.py b/src/generator2/generator2_full/models/models_response_createChatpost201.py new file mode 100644 index 0000000..289211b --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createChatpost201.py @@ -0,0 +1,43 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + id: Optional[int] = Field( + None, description="Идентификатор беседы или канала", + ) + owner_id: Optional[int] = Field( + None, + description="Идентификатор пользователя, создавшего беседу или канал", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + last_message_at: Optional[str] = Field( + None, + description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + meet_room_url: Optional[str] = Field( + None, description="Ссылка на Видеочат", + ) + + +class ResponseCreatechatPost201(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createChatpost400.py b/src/generator2/generator2_full/models/models_response_createChatpost400.py new file mode 100644 index 0000000..3d5be37 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createChatpost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatechatPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost422.py b/src/generator2/generator2_full/models/models_response_createChatpost422.py new file mode 100644 index 0000000..9ee79aa --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createChatpost422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatechatPost422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost201.py b/src/generator2/generator2_full/models/models_response_createMessagepost201.py new file mode 100644 index 0000000..a7da269 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createMessagepost201.py @@ -0,0 +1,104 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseCreatemessagePost201(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost400.py b/src/generator2/generator2_full/models/models_response_createMessagepost400.py new file mode 100644 index 0000000..b484245 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createMessagepost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatemessagePost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost201.py b/src/generator2/generator2_full/models/models_response_createTaskpost201.py new file mode 100644 index 0000000..749ca91 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createTaskpost201.py @@ -0,0 +1,66 @@ +from enum import IntEnum, StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + value: Optional[str] = Field(None, description="Значение поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + + +class enum_kind(StrEnum): + call = "call" + meeting = "meeting" + reminder = "reminder" + event = "event" + email = "email" + + +class enum_priority(IntEnum): + priority_1 = 1 + priority_2 = 2 + priority_3 = 3 + + +class Data(BaseModel): + kind: enum_kind = Field(..., description="Тип напоминания") + content: str = Field(..., description="Описание напоминания") + due_at: str = Field( + ..., description="Срок выполнения напоминания (ISO-8601)", + ) + priority: Optional[enum_priority] = Field( + None, + description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", + ) + performer_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов пользователей", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="No docstring provided", + ) + id: Optional[int] = Field( + None, description="Идентификатор созданного напоминания", + ) + user_id: Optional[int] = Field( + None, description="Идентификатор пользователя-создателя", + ) + status: Optional[str] = Field(None, description="Статус напоминания") + created_at: Optional[str] = Field( + None, description="Дата и время создания", + ) + + +class ResponseCreatetaskPost201(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost400.py b/src/generator2/generator2_full/models/models_response_createTaskpost400.py new file mode 100644 index 0000000..7b83d43 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createTaskpost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatetaskPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost200.py b/src/generator2/generator2_full/models/models_response_createThreadpost200.py new file mode 100644 index 0000000..93e2199 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createThreadpost200.py @@ -0,0 +1,23 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред.", + ) + message_chat_id: Optional[int] = Field( + None, description="Идентификатор чата сообщения.", + ) + updated_at: Optional[str] = Field( + None, + description="Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", + ) + + +class ResponseCreatethreadPost200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost400.py b/src/generator2/generator2_full/models/models_response_createThreadpost400.py new file mode 100644 index 0000000..aab3648 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createThreadpost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatethreadPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py new file mode 100644 index 0000000..c80757d --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseDeletemessagereactionsDelete400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_editMessageput200.py b/src/generator2/generator2_full/models/models_response_editMessageput200.py new file mode 100644 index 0000000..2daa577 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_editMessageput200.py @@ -0,0 +1,104 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseEditmessagePut200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_editMessageput400.py b/src/generator2/generator2_full/models/models_response_editMessageput400.py new file mode 100644 index 0000000..cb7e60d --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_editMessageput400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseEditmessagePut400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatget200.py b/src/generator2/generator2_full/models/models_response_getChatget200.py new file mode 100644 index 0000000..26c9d0a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatget200.py @@ -0,0 +1,43 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + id: Optional[int] = Field( + None, description="Идентификатор беседы или канала", + ) + owner_id: Optional[int] = Field( + None, + description="Идентификатор пользователя, создавшего беседу или канал", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + last_message_at: Optional[str] = Field( + None, + description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + meet_room_url: Optional[str] = Field( + None, description="Ссылка на Видеочат", + ) + + +class ResponseGetchatGet200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getChatget400.py b/src/generator2/generator2_full/models/models_response_getChatget400.py new file mode 100644 index 0000000..5cf12e6 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetchatGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget200.py b/src/generator2/generator2_full/models/models_response_getChatsget200.py new file mode 100644 index 0000000..68c2eec --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatsget200.py @@ -0,0 +1,45 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + id: Optional[int] = Field( + None, description="Идентификатор беседы или канала", + ) + owner_id: Optional[int] = Field( + None, + description="Идентификатор пользователя, создавшего беседу или канал", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + last_message_at: Optional[str] = Field( + None, + description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + meet_room_url: Optional[str] = Field( + None, description="Ссылка на Видеочат", + ) + + +class ResponseGetchatsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget400.py b/src/generator2/generator2_full/models/models_response_getChatsget400.py new file mode 100644 index 0000000..0893c6b --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetchatsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget422.py b/src/generator2/generator2_full/models/models_response_getChatsget422.py new file mode 100644 index 0000000..89c7937 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatsget422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetchatsGet422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py new file mode 100644 index 0000000..9c132b3 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py @@ -0,0 +1,23 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Название поля") + name: Optional[str] = Field(None, description="Идентификатор поля") + data_type: Optional[enum_data_type] = Field(None, description="тип поля") + + +class ResponseGetcommonmethodsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py new file mode 100644 index 0000000..f2ae8ba --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetcommonmethodsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py new file mode 100644 index 0000000..a798652 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py @@ -0,0 +1,90 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + value: Optional[str] = Field(None, description="Значение") + + +class User_status(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class enum_role(StrEnum): + admin = "admin" + user = "user" + multi_guest = "multi_guest" + + +class enum_invite_status(StrEnum): + confirmed = "confirmed" + sent = "sent" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор пользователя") + first_name: Optional[str] = Field(None, description="Имя") + last_name: Optional[str] = Field(None, description="Фамилия") + nickname: Optional[str] = Field(None, description="Имя пользователя") + email: Optional[str] = Field(None, description="Электронная почта") + phone_number: Optional[str] = Field(None, description="Телефон") + department: Optional[str] = Field(None, description="Департамент") + role: Optional[enum_role] = Field( + None, + description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", + ) + suspended: Optional[bool] = Field( + None, + description="Деактивация пользователя. При значении true пользователь является деактивированным.", + ) + invite_status: Optional[enum_invite_status] = Field( + None, + description="Статус приглашения: confirmed (принято), sent (отправлено)", + ) + list_tags: Optional[List[str]] = Field( + None, description="Массив тегов, привязанных к сотруднику", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="Дополнительные поля сотрудника", + ) + bot: Optional[bool] = Field( + None, description="Тип: пользователь (false) или бот (true)", + ) + user_status: Optional[User_status] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) + title: Optional[str] = Field(None, description="Должность") + created_at: Optional[str] = Field( + None, + description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + time_zone: Optional[str] = Field( + None, description="Часовой пояс пользователя", + ) + image_url: Optional[str] = Field( + None, description="Ссылка на скачивание аватарки", + ) + + +class ResponseGetemployeeGet200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py new file mode 100644 index 0000000..a22237a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetemployeeGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py new file mode 100644 index 0000000..6f24174 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py @@ -0,0 +1,92 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + value: Optional[str] = Field(None, description="Значение") + + +class User_status(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class enum_role(StrEnum): + admin = "admin" + user = "user" + multi_guest = "multi_guest" + + +class enum_invite_status(StrEnum): + confirmed = "confirmed" + sent = "sent" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор пользователя") + first_name: Optional[str] = Field(None, description="Имя") + last_name: Optional[str] = Field(None, description="Фамилия") + nickname: Optional[str] = Field(None, description="Имя пользователя") + email: Optional[str] = Field(None, description="Электронная почта") + phone_number: Optional[str] = Field(None, description="Телефон") + department: Optional[str] = Field(None, description="Департамент") + role: Optional[enum_role] = Field( + None, + description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", + ) + suspended: Optional[bool] = Field( + None, + description="Деактивация пользователя. При значении true пользователь является деактивированным.", + ) + invite_status: Optional[enum_invite_status] = Field( + None, + description="Статус приглашения: confirmed (принято), sent (отправлено)", + ) + list_tags: Optional[List[str]] = Field( + None, description="Массив тегов, привязанных к сотруднику", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="Дополнительные поля сотрудника", + ) + bot: Optional[bool] = Field( + None, description="Тип: пользователь (false) или бот (true)", + ) + user_status: Optional[User_status] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) + title: Optional[str] = Field(None, description="Должность") + created_at: Optional[str] = Field( + None, + description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + time_zone: Optional[str] = Field( + None, description="Часовой пояс пользователя", + ) + image_url: Optional[str] = Field( + None, description="Ссылка на скачивание аватарки", + ) + + +class ResponseGetemployeesGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget200.py b/src/generator2/generator2_full/models/models_response_getListMessageget200.py new file mode 100644 index 0000000..c187528 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getListMessageget200.py @@ -0,0 +1,106 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseGetlistmessageGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget400.py b/src/generator2/generator2_full/models/models_response_getListMessageget400.py new file mode 100644 index 0000000..9bc441d --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getListMessageget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetlistmessageGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py new file mode 100644 index 0000000..ce9da6a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py @@ -0,0 +1,20 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + user_id: Optional[int] = Field( + None, description="Идентификатор пользователя, оставившего реакцию.", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", + ) + code: Optional[str] = Field(None, description="Emoji символ реакции.") + + +class ResponseGetmessagereactionsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py new file mode 100644 index 0000000..369fcdf --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetmessagereactionsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageget200.py b/src/generator2/generator2_full/models/models_response_getMessageget200.py new file mode 100644 index 0000000..92d3d71 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageget200.py @@ -0,0 +1,104 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseGetmessageGet200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getMessageget400.py b/src/generator2/generator2_full/models/models_response_getMessageget400.py new file mode 100644 index 0000000..9c51172 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetmessageGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getStatusget200.py b/src/generator2/generator2_full/models/models_response_getStatusget200.py new file mode 100644 index 0000000..0d09a11 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getStatusget200.py @@ -0,0 +1,19 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class ResponseGetstatusGet200(BaseModel): + data: Optional[Data] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget200.py b/src/generator2/generator2_full/models/models_response_getTagget200.py new file mode 100644 index 0000000..ef7a650 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagget200.py @@ -0,0 +1,18 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор тега") + name: Optional[str] = Field(None, description="Название тега") + users_count: Optional[int] = Field( + None, description="Количество сотрудников, которые имеют этот тег", + ) + + +class ResponseGettagGet200(BaseModel): + data: Optional[Data] = Field( + None, + description="Для получения тега вам необходимо знать его id и указать его в URL запроса.", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget400.py b/src/generator2/generator2_full/models/models_response_getTagget400.py new file mode 100644 index 0000000..a3b9fe0 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGettagGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py new file mode 100644 index 0000000..d835b3a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py @@ -0,0 +1,68 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + value: Optional[str] = Field(None, description="Значение") + + +class enum_role(StrEnum): + admin = "admin" + user = "user" + multi_guest = "multi_guest" + + +class enum_invite_status(StrEnum): + confirmed = "confirmed" + sent = "sent" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор пользователя") + first_name: Optional[str] = Field(None, description="Имя") + last_name: Optional[str] = Field(None, description="Фамилия") + nickname: Optional[str] = Field(None, description="Имя пользователя") + email: Optional[str] = Field(None, description="Электронная почта") + phone_number: Optional[str] = Field(None, description="Телефон") + department: Optional[str] = Field(None, description="Департамент") + role: Optional[enum_role] = Field( + None, + description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", + ) + suspended: Optional[bool] = Field( + None, + description="Деактивация пользователя. При значении true пользователь является деактивированным.", + ) + invite_status: Optional[enum_invite_status] = Field( + None, + description="Статус приглашения: confirmed (принято), sent (отправлено)", + ) + list_tags: Optional[List[str]] = Field( + None, description="Массив тегов, привязанных к сотруднику", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="Дополнительные поля сотрудника", + ) + bot: Optional[bool] = Field( + None, description="Тип: пользователь (false) или бот (true)", + ) + + +class ResponseGettagsemployeesGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py new file mode 100644 index 0000000..a7c67de --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGettagsemployeesGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget200.py b/src/generator2/generator2_full/models/models_response_getTagsget200.py new file mode 100644 index 0000000..a6f0b4b --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsget200.py @@ -0,0 +1,17 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор тега") + name: Optional[str] = Field(None, description="Название тега") + users_count: Optional[int] = Field( + None, description="Количество сотрудников, которые имеют этот тег", + ) + + +class ResponseGettagsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget400.py b/src/generator2/generator2_full/models/models_response_getTagsget400.py new file mode 100644 index 0000000..0015a61 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGettagsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getUploadspost200.py b/src/generator2/generator2_full/models/models_response_getUploadspost200.py new file mode 100644 index 0000000..0d31122 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getUploadspost200.py @@ -0,0 +1,39 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class ResponseGetuploadsPost200(BaseModel): + Content_Disposition: Optional[str] = Field( + None, + description="Используемый заголовок", + alilas="Content-Disposition", + ) + acl: Optional[str] = Field(None, description="Уровень безопасности") + policy: Optional[str] = Field( + None, description="Уникальный policy для загрузки файла", + ) + x_amz_credential: Optional[str] = Field( + None, + description="x-amz-credential для загрузки файла", + alilas="x-amz-credential", + ) + x_amz_algorithm: Optional[str] = Field( + None, description="Используемый алгоритм", alilas="x-amz-algorithm", + ) + x_amz_date: Optional[str] = Field( + None, + description="Уникальный x-amz-date для загрузки файла", + alilas="x-amz-date", + ) + x_amz_signature: Optional[str] = Field( + None, + description="Уникальная подпись для загрузки файла", + alilas="x-amz-signature", + ) + key: Optional[str] = Field( + None, description="Уникальный ключ для загрузки файла", + ) + direct_url: Optional[str] = Field( + None, description="Адрес для загрузки файла", + ) diff --git a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py new file mode 100644 index 0000000..3e430a1 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseLeavechatDelete400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py new file mode 100644 index 0000000..5dd1dbd --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePostmemberstochatsPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py new file mode 100644 index 0000000..bdf933f --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePostmemberstochatsPost422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py new file mode 100644 index 0000000..0d305f2 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePostmessagereactionsPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py new file mode 100644 index 0000000..e0385a7 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePosttagstochatsPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py new file mode 100644 index 0000000..8b157bf --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePosttagstochatsPost422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput201.py b/src/generator2/generator2_full/models/models_response_putStatusput201.py new file mode 100644 index 0000000..db4d1ca --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_putStatusput201.py @@ -0,0 +1,19 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class ResponsePutstatusPut201(BaseModel): + data: Optional[Data] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput400.py b/src/generator2/generator2_full/models/models_response_putStatusput400.py new file mode 100644 index 0000000..74a54e1 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_putStatusput400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePutstatusPut400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/repository/pachca_generator1-1.0.0-py3-none-any.whl b/src/repository/pachca_generator1-1.0.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..89d3af778d40fbf8b6dbfe60b282f2fbb1582155 GIT binary patch literal 128944 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 G22F?Nk9x` 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 Aj{pDw literal 0 HcmV?d00001 From c0bffa0b3d2bb0a4b8de5bc53ad11421fc5d3d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 08:03:37 +0300 Subject: [PATCH 242/296] start --- src/generator1/README.md | 14 ++----- src/generator1/client_servis.py | 18 ++++----- src/generator1/generator.py | 37 +++++++++++++++++++ .../templates/endpoint_module.py.jinja | 6 +-- 4 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 src/generator1/generator.py diff --git a/src/generator1/README.md b/src/generator1/README.md index b942afc..0f3cd4d 100644 --- a/src/generator1/README.md +++ b/src/generator1/README.md @@ -7,16 +7,8 @@ pip install openapi-python-client 2. Сгенерировать клиент командой -openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite +python generator.py generate -3. Запустить скрипт-генератор +3. Запустить скрипт-пример запроса -python script.py - -4. Установить pachca-api-open-api-3-0-client в venv командой - -pip install ./pachca-api-open-api-3-0-client - -5. Запустить скрипт-пример запроса - -python pachca.py \ No newline at end of file +python generator.py test diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index fae0ea2..03e7d8f 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -45,7 +45,7 @@ class AuthenticatedClient: prefix: str = "Bearer" auth_header_name: str = "Authorization" - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + async def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": """Get a new client matching this one with additional headers""" if self._client is not None: self._client.headers.update(headers) @@ -53,7 +53,7 @@ def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": self._async_client.headers.update(headers) return evolve(self, headers={**self._headers, **headers}) - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + async def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": """Get a new client matching this one with additional cookies""" if self._client is not None: self._client.cookies.update(cookies) @@ -61,7 +61,7 @@ def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": self._async_client.cookies.update(cookies) return evolve(self, cookies={**self._cookies, **cookies}) - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + async def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": """Get a new client matching this one with a new timeout (in seconds)""" if self._client is not None: self._client.timeout = timeout @@ -69,7 +69,7 @@ def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": self._async_client.timeout = timeout return evolve(self, timeout=timeout) - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + async def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": """Manually set the underlying httpx.Client **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. @@ -77,7 +77,7 @@ def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": self._client = client return self - def get_httpx_client(self) -> httpx.Client: + async def get_httpx_client(self) -> httpx.Client: """Get the underlying httpx.Client, constructing a new one if not previously set""" if self._client is None: self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token @@ -92,16 +92,16 @@ def get_httpx_client(self) -> httpx.Client: ) return self._client - def __enter__(self) -> "AuthenticatedClient": + async def __enter__(self) -> "AuthenticatedClient": """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" self.get_httpx_client().__enter__() return self - def __exit__(self, *args: Any, **kwargs: Any) -> None: + async def __exit__(self, *args: Any, **kwargs: Any) -> None: """Exit a context manager for internal httpx.Client (see httpx docs)""" self.get_httpx_client().__exit__(*args, **kwargs) - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + async def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": """Manually the underlying httpx.AsyncClient **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. @@ -109,7 +109,7 @@ def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Authentica self._async_client = async_client return self - def get_async_httpx_client(self) -> httpx.AsyncClient: + async def get_async_httpx_client(self) -> httpx.AsyncClient: """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" if self._async_client is None: self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token diff --git a/src/generator1/generator.py b/src/generator1/generator.py new file mode 100644 index 0000000..10a92e5 --- /dev/null +++ b/src/generator1/generator.py @@ -0,0 +1,37 @@ +import subprocess +import sys + +def run_command(command): + """Функция для выполнения команды в терминале.""" + try: + subprocess.run(command, check=True, shell=True, text=True) + print(f"Команда выполнена: {command}") + except subprocess.CalledProcessError as e: + print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") + +def generate_client(): + """Генерация клиента и запуск скрипта-генератора.""" + print("Генерация клиента...") + run_command("openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite") + run_command("python script.py") + +def install_and_run_tests(): + """Установка пакета и запуск тест-запросов.""" + print("Установка пакета и запуск тест-запросов...") + run_command("pip install ./pachca-api-open-api-3-0-client") + run_command("python pachca.py") + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Использование: python generator.py [generate|test]") + sys.exit(1) + + option = sys.argv[1] + + if option == "generate": + generate_client() + elif option == "test": + install_and_run_tests() + else: + print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") + sys.exit(1) diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index 5e5eae7..4cc3003 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -19,7 +19,7 @@ from .logger_setup import setup_logging {% set return_string = endpoint.response_type() %} {% set parsed_responses = (endpoint.responses | length > 0) and return_string != "Any" %} -def _get_kwargs_{{ endpoint.name }}(self, +async def _get_kwargs_{{ endpoint.name }}(self, {{ arguments(endpoint, include_client=False) | indent(4) }} ) -> dict[str, Any]: {{ header_params(endpoint) | indent(4) }} @@ -71,7 +71,7 @@ def _get_kwargs_{{ endpoint.name }}(self, return _kwargs -def _parse_response_{{ endpoint.name }}(self, response: httpx.Response) -> Optional[{{ return_string }}]: +async def _parse_response_{{ endpoint.name }}(self, response: httpx.Response) -> Optional[{{ return_string }}]: {% for response in endpoint.responses %} self.logger.info(f"Получен ответ с кодом: {response.status_code} для {{ endpoint.name }}") if response.status_code == {{ response.status_code.value }}: @@ -93,7 +93,7 @@ def _parse_response_{{ endpoint.name }}(self, response: httpx.Response) -> Optio return response_error -def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> Response[{{ return_string }}]: +async def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> Response[{{ return_string }}]: self.logger.debug("Преобразование JSON в Python для {{ endpoint.name }}.") return Response( status_code=HTTPStatus(response.status_code), From 0fa8ab79a2f8f2483a5ac243ac4b4d9329d99453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 08:04:22 +0300 Subject: [PATCH 243/296] Merge branch 'Removal_of_the_general_structure' into generator1 --- README.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 3bf5122..9fb9fff 100644 --- a/README.md +++ b/README.md @@ -117,21 +117,13 @@ _src/generator1/_ .\venv\scripts\activate pip install -r requirements.txt ``` -3. **Запустите генерацию клиента**: - ```bash - openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite - ``` -4. **Запустите скрипт-генератор**: +3. **Запустите генерацию клиента:**: ```bash - python script.py + python generator.py generate ``` -5. **Установить pachca-api-open-api-3-0-client в venv командой**: - ```bash - pip install ./pachca-api-open-api-3-0-client - ``` -6. **Запустите пример запроса**: +4. **Запустите пример запроса**: ```bash - python pachca.py + python generator.py test ``` ## 💡 Команда генератора From 0611be67b24be0b864fbd5ba0c3d1ac2c89ac86b Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 10:55:26 +0300 Subject: [PATCH 244/296] add leave chat test --- src/generator2/generator2_full/pachca.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 546ab47..646d8f0 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -164,6 +164,12 @@ async def run_pachca(): ) logger.debug(f'create_task: {response_create_task}') + # Метод для того чтобы покинуть конкретный чат (беседу) + response_leave_chat = await pachca.leave_chat( + id=created_chat.data.id + ) + logger.debug(f'leave_chat: {response_leave_chat.data[0].id}') + response_get_users = await pachca.get_employees() logger.debug(f'One user from list: {response_get_users.data[0].id}') From 2cd3f339252e91dfa4924f51bdc1e7ceaa2375d7 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 10:56:23 +0300 Subject: [PATCH 245/296] generator log file path linked to generator2 folder --- src/generator2/services/constants.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/generator2/services/constants.py b/src/generator2/services/constants.py index d586289..56bab28 100644 --- a/src/generator2/services/constants.py +++ b/src/generator2/services/constants.py @@ -1,3 +1,4 @@ +import os from pathlib import Path import sys @@ -38,6 +39,7 @@ DEFAULT_VALUE_SORT_FIELD = 'id' TYPE_SORT_FIELD = 'str' -LOG_FILE_NAME = 'client_generator.log' +BASE_DIR = Path(os.path.dirname(os.path.abspath(__file__))).parent +LOG_FILE_NAME = os.path.join(BASE_DIR, "client_generator.log") GENERATED_CLIENT_FOLDER = 'generator2_full' From 3362c3f98aa405917b7f00924584e4f44e1cb47f Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 11:14:39 +0300 Subject: [PATCH 246/296] add example .env --- src/generator2/.env.example | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/generator2/.env.example diff --git a/src/generator2/.env.example b/src/generator2/.env.example new file mode 100644 index 0000000..0f17c0f --- /dev/null +++ b/src/generator2/.env.example @@ -0,0 +1 @@ +TOKEN=ваштокен \ No newline at end of file From 9974100cb87a6705d3f61351335fe173ba500b8b Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 11:19:12 +0300 Subject: [PATCH 247/296] fix readme --- README.md | 4 ++-- src/generator2/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3bf5122..5764ca3 100644 --- a/README.md +++ b/README.md @@ -247,9 +247,9 @@ _src/generator2/_ ## 🚀 Установка и использование -### 🛠️ Инструкция (работать в папке `generator2` при активированном `venv`): +### 🛠️ Инструкция (работать в папке `src` при активированном `venv`): 1. **Создайте файл `.env`** в директории `generator2`, с токеном для работы с API "Пачка". -Пример файла: +Пример файла .env.example: ``` TOKEN=ваштокен ``` diff --git a/src/generator2/README.md b/src/generator2/README.md index 3b97970..5789f6d 100644 --- a/src/generator2/README.md +++ b/src/generator2/README.md @@ -1,6 +1,6 @@ -Инструкция (работать в папке generator2 при активированном venv): +### Инструкция (работать в папке `src` при активированном venv): -1. Создать файл .env в директории generator2, с токеном для работы с API пачки. Пример файла: +1. Создать файл .env в директории generator2, с токеном для работы с API пачки. Пример файла .env.example: ``` TOKEN=ваштокен From b6fc67e0c454b5f6636c155d3a3fd9d553a96177 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 11:55:00 +0300 Subject: [PATCH 248/296] add get_uploads tests --- src/generator2/generator2_full/pachca.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 646d8f0..01f1841 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -198,6 +198,11 @@ async def run_pachca(): # Удалить статус текущему пользователю, обладателю токена. response_del_status = await pachca.del_status() logger.debug(f'del_status: {response_del_status}') + + # Получения подписи и ключа для загрузки файла + response_get_uploads = pachca.get_uploads() + logger.debug(f'del_status: {response_get_uploads}') + logger.debug('*' * 60) asyncio.run(run_pachca()) From 4ebe64e5fb642ea8405a693d4f99fc6fc37335b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 13:00:11 +0300 Subject: [PATCH 249/296] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D1=81=D1=81=D0=B0=20Bot=20=D0=B8=20=D0=B8=D1=85=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2=20=D0=B2=20=D0=B3=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D1=80=D0=B8=D1=80=D1=83=D0=B5=D0=BC=D1=8B=D1=85=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=D1=85=20=D0=B7=D0=B0=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=81=D0=B0=20=D0=BD=D0=B0=20=D0=B0=D1=81=D1=81=D0=B8?= =?UTF-8?q?=D0=BD=D1=85=D1=80=D0=BE=D0=BD=D0=BD=D1=8B=D0=B5.=20request=5Fm?= =?UTF-8?q?ethods=5Fgenerator.py=20=D1=81=D1=82=D1=80.42,70-71.=20=D0=94?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82=D0=B0=20TOKEN=5FTYPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generator2/generator2_full/bot.py | 12 ++++++----- src/generator2/generator2_full/constants.py | 1 + src/generator2/generator2_full/pachca.py | 2 +- src/generator2/request_methods_generator.py | 24 ++++++++++----------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/generator2/generator2_full/bot.py b/src/generator2/generator2_full/bot.py index 7239487..5a37de0 100644 --- a/src/generator2/generator2_full/bot.py +++ b/src/generator2/generator2_full/bot.py @@ -1,9 +1,10 @@ import importlib import inspect +from typing import Callable import httpx -from .constants import URL, PARAM_NAME_SORT_FIELD, PARAM_NAME_SORT +from .constants import PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, TOKEN_TYPE, URL class RequestMethodsCollector(type): @@ -20,7 +21,7 @@ def __new__(cls, name, bases, dct): ).__new__(cls, name, bases, dct) @staticmethod - def collect_methods(module) -> dict[str, object]: + def collect_methods(module) -> dict[str, Callable]: """Собирает сгенерированные функции из модуля request_methods.py""" dict_func = {} @@ -39,9 +40,10 @@ def collect_methods(module) -> dict[str, object]: class Bot(metaclass=RequestMethodsCollector): base_url = URL + token_type = TOKEN_TYPE def __init__(self, token): - self.token = token + self.token = f'{self.token_type} {token}' async def get_client(self): return httpx.AsyncClient( @@ -49,14 +51,14 @@ async def get_client(self): headers={'Authorization': self.token}, ) - def format_url( + async def format_url( self, url_template: str, path_param: dict[str, int] = None, ): return url_template.format(**path_param) - def filter_query_params(self, **kwargs): + async def filter_query_params(self, **kwargs): if PARAM_NAME_SORT in kwargs or PARAM_NAME_SORT_FIELD in kwargs: sort = kwargs.pop(PARAM_NAME_SORT) sort_field = kwargs.pop(PARAM_NAME_SORT_FIELD) diff --git a/src/generator2/generator2_full/constants.py b/src/generator2/generator2_full/constants.py index 7c8a0f6..7055256 100644 --- a/src/generator2/generator2_full/constants.py +++ b/src/generator2/generator2_full/constants.py @@ -2,6 +2,7 @@ URL = 'https://api.pachca.com/api/shared/v1' PARAM_NAME_SORT = 'sort' PARAM_NAME_SORT_FIELD = 'sort_field' +TOKEN_TYPE = 'Bearer' # Logger constants LOG_FILE_NAME = 'pachca_log.log' diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 546ab47..653f4ea 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -18,7 +18,7 @@ logger = setup_logging('pachca_log') if __name__ == '__main__': - pachca = Bot(token=f'Bearer {os.environ.get("TOKEN", "LOOKUP FAILED!")}') + pachca = Bot(token=f'{os.environ.get("TOKEN", "LOOKUP FAILED!")}') message_test = Createmessage(message=Message( entity_type="discussion", diff --git a/src/generator2/request_methods_generator.py b/src/generator2/request_methods_generator.py index 3508bfd..6c9d6ad 100644 --- a/src/generator2/request_methods_generator.py +++ b/src/generator2/request_methods_generator.py @@ -5,17 +5,16 @@ from httpx import codes from openapi_parser import parse -from openapi_parser.specification import ( - DataType, Path, Specification, Operation, Parameter -) +from openapi_parser.specification import (DataType, Operation, Parameter, Path, + Specification) -from .services.constants import ( - SPECIFICATION_FILE_NAME, PARAM_TYPE_KEY, PARAM_DEFAULT_KEY, - SCHEMA_SORT_ID, PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, - PARAM_LOCATION_QUERY, PARAM_LOCATION_PATH, PREFIX_RESPONSE, - PREFIX_REQUEST, DEFAULT_VALUE_SORT_FIELD, TYPE_SORT_FIELD, - GENERATED_CLIENT_FOLDER -) +from .services.constants import (DEFAULT_VALUE_SORT_FIELD, + GENERATED_CLIENT_FOLDER, PARAM_DEFAULT_KEY, + PARAM_LOCATION_PATH, PARAM_LOCATION_QUERY, + PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, + PARAM_TYPE_KEY, PREFIX_REQUEST, + PREFIX_RESPONSE, SCHEMA_SORT_ID, + SPECIFICATION_FILE_NAME, TYPE_SORT_FIELD) def format_path_params(param_path: dict[str, Union[str, dict]]) -> str: @@ -40,7 +39,7 @@ def generate_url_template( """Генерирует строку с форматированным URL для функции.""" if param_path: path_params = format_path_params(param_path) - return f"url = self.format_url('{url}', {{{path_params}}})" + return f"url = await self.format_url('{url}', {{{path_params}}})" return f"url = '{url}'" @@ -137,7 +136,8 @@ def get_template_methods( f" -> {name_response_scheme}" if name_response_scheme else "" ) filter_params_code = ( - f"\n query_params=self.filter_query_params({filter_params})" + f"\n query_params = await self.filter_query_params" + f"({filter_params})" if filter_params else "" ) From a75b9f99dda7543ffbb37d47727b660ed289a417 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 17:07:15 +0300 Subject: [PATCH 250/296] added tags tests --- src/generator2/generator2_full/pachca.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 01f1841..bca36f2 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -203,6 +203,16 @@ async def run_pachca(): response_get_uploads = pachca.get_uploads() logger.debug(f'del_status: {response_get_uploads}') + response_get_tags_employees = pachca.get_tags_employees( + id=1234 + ) + logger.debug(f'get_tags_employees: {response_get_tags_employees}') + + response_get_tag = pachca.get_tag( + id=1234 + ) + logger.debug(f'get_tag: {response_get_tag}') + logger.debug('*' * 60) asyncio.run(run_pachca()) From 8a54539fafe1929e99df196ae15bd2d435e45c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 17:17:58 +0300 Subject: [PATCH 251/296] refactoring --- ...ds_generator.py => class_bot_generator.py} | 44 +++++++----- src/generator2/generator2_full/bot.py | 70 ------------------- .../generator2_full/request_methods.py | 0 src/generator2/generator_starter.py | 6 +- src/generator2/services/constants.py | 41 +++++++++++ src/generator2/yaml_processor.py | 3 +- 6 files changed, 72 insertions(+), 92 deletions(-) rename src/generator2/{request_methods_generator.py => class_bot_generator.py} (92%) delete mode 100644 src/generator2/generator2_full/request_methods.py diff --git a/src/generator2/request_methods_generator.py b/src/generator2/class_bot_generator.py similarity index 92% rename from src/generator2/request_methods_generator.py rename to src/generator2/class_bot_generator.py index 6c9d6ad..022c8b0 100644 --- a/src/generator2/request_methods_generator.py +++ b/src/generator2/class_bot_generator.py @@ -14,7 +14,9 @@ PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, PARAM_TYPE_KEY, PREFIX_REQUEST, PREFIX_RESPONSE, SCHEMA_SORT_ID, - SPECIFICATION_FILE_NAME, TYPE_SORT_FIELD) + SPECIFICATION_FILE_NAME, TEMPLATE_CLASS_BOT, + TEMPLATE_IMPORT_FOR_CLASS_BOT, + TYPE_SORT_FIELD) def format_path_params(param_path: dict[str, Union[str, dict]]) -> str: @@ -99,13 +101,17 @@ def generate_response_handling( """Генерирует логику обработки ответа от сервера.""" response_handling = "" if name_response_scheme: - response_handling += f""" - if response.is_success: - return {name_response_scheme}.model_validate_json(response.text)""" + response_handling += ( + '\n if response.is_success:\n' + f' return {name_response_scheme}' + '.model_validate_json(response.text)' + ) if name_error_scheme: - response_handling += f""" - if response.is_client_error: - return {name_error_scheme}.model_validate_json(response.text)""" + response_handling += ( + '\n if response.is_client_error:\n' + f' return {name_error_scheme}' + '.model_validate_json(response.text)' + ) return response_handling @@ -136,20 +142,20 @@ def get_template_methods( f" -> {name_response_scheme}" if name_response_scheme else "" ) filter_params_code = ( - f"\n query_params = await self.filter_query_params" + f"\n query_params = await self.filter_query_params" f"({filter_params})" if filter_params else "" ) return f""" -async def {name_func}({function_params}){response_annotation}: - {docstring} - client = await self.get_client() - async with client: - {format_url}{filter_params_code} - {request_handling}{response_handling} - return None + async def {name_func}({function_params}){response_annotation}: + {docstring} + client = await self.get_client() + async with client: + {format_url}{filter_params_code} + {request_handling}{response_handling} + return None """ @@ -368,16 +374,18 @@ def get_obj_openapi_spec( return parse(spec_string=spec_openapi) -def generation_methods_request( +def generation_class_bot( templates: list, import_templates: list, - file=f'./{__package__}/{GENERATED_CLIENT_FOLDER}/request_methods.py', + file=f'./{__package__}/{GENERATED_CLIENT_FOLDER}/bot.py', ): with open( file, 'w', encoding='utf-8', ) as file: + file.write(f'{TEMPLATE_IMPORT_FOR_CLASS_BOT}') for module_name in import_templates: file.write(f'{module_name}\n') + file.write(f'\n {TEMPLATE_CLASS_BOT}') for template in templates: file.write(template) @@ -388,7 +396,7 @@ def generate(): templates, import_templates = template_generation(paths) - generation_methods_request( + generation_class_bot( templates=templates, import_templates=import_templates ) diff --git a/src/generator2/generator2_full/bot.py b/src/generator2/generator2_full/bot.py index 5a37de0..e69de29 100644 --- a/src/generator2/generator2_full/bot.py +++ b/src/generator2/generator2_full/bot.py @@ -1,70 +0,0 @@ -import importlib -import inspect -from typing import Callable - -import httpx - -from .constants import PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, TOKEN_TYPE, URL - - -class RequestMethodsCollector(type): - - def __new__(cls, name, bases, dct): - req_methods = importlib.import_module('.request_methods', __package__) - request_methods = cls.collect_methods(req_methods) - - for name_method, method in request_methods.items(): - dct[name_method] = method - - return super( - RequestMethodsCollector, cls, - ).__new__(cls, name, bases, dct) - - @staticmethod - def collect_methods(module) -> dict[str, Callable]: - """Собирает сгенерированные функции из модуля request_methods.py""" - dict_func = {} - - for name, obj in inspect.getmembers(module): - if inspect.isfunction(obj): - dict_func[name] = obj - - if not dict_func: - raise ValueError( - f"В модуле {module.__name__} " - "отсутствуют сгенерированные функции", - ) - - return dict_func - - -class Bot(metaclass=RequestMethodsCollector): - base_url = URL - token_type = TOKEN_TYPE - - def __init__(self, token): - self.token = f'{self.token_type} {token}' - - async def get_client(self): - return httpx.AsyncClient( - base_url=self.base_url, - headers={'Authorization': self.token}, - ) - - async def format_url( - self, - url_template: str, - path_param: dict[str, int] = None, - ): - return url_template.format(**path_param) - - async def filter_query_params(self, **kwargs): - if PARAM_NAME_SORT in kwargs or PARAM_NAME_SORT_FIELD in kwargs: - sort = kwargs.pop(PARAM_NAME_SORT) - sort_field = kwargs.pop(PARAM_NAME_SORT_FIELD) - kwargs[f'sort[{sort_field}]'] = sort - - return { - str(key): value - for key, value in kwargs.items() if value is not None - } diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator2/generator_starter.py b/src/generator2/generator_starter.py index 192fe78..0f9890e 100644 --- a/src/generator2/generator_starter.py +++ b/src/generator2/generator_starter.py @@ -3,7 +3,7 @@ from .services.constants import GENERATED_CLIENT_FOLDER from .services.logger_setup import setup_logging -from .request_methods_generator import generate +from .class_bot_generator import generate from .yaml_processor import process_endpoints @@ -34,7 +34,7 @@ def generate_client(): subprocess.run( [ 'black', - f'{dir_path}/request_methods.py', + f'{dir_path}/bot.py', '--line-length', '79' ], @@ -54,7 +54,7 @@ def generate_client(): [ 'ruff', 'check', - f'{dir_path}/request_methods.py', + f'{dir_path}/bot.py', '--fix', '--silent' ] diff --git a/src/generator2/services/constants.py b/src/generator2/services/constants.py index d586289..9cc5838 100644 --- a/src/generator2/services/constants.py +++ b/src/generator2/services/constants.py @@ -41,3 +41,44 @@ LOG_FILE_NAME = 'client_generator.log' GENERATED_CLIENT_FOLDER = 'generator2_full' + + +TEMPLATE_CLASS_BOT = """ +class Bot: + base_url = URL + token_type = TOKEN_TYPE + + def __init__(self, token): + self.token = f'{self.token_type} {token}' + + async def get_client(self): + return httpx.AsyncClient( + base_url=self.base_url, + headers={'Authorization': self.token}, + ) + + async def format_url( + self, + url_template: str, + path_param: dict[str, int] = None, + ): + return url_template.format(**path_param) + + async def filter_query_params(self, **kwargs): + if PARAM_NAME_SORT in kwargs or PARAM_NAME_SORT_FIELD in kwargs: + sort = kwargs.pop(PARAM_NAME_SORT) + sort_field = kwargs.pop(PARAM_NAME_SORT_FIELD) + kwargs[f'sort[{sort_field}]'] = sort + + return { + str(key): value + for key, value in kwargs.items() if value is not None + } + +""" + +TEMPLATE_IMPORT_FOR_CLASS_BOT = """ +import httpx + +from .constants import PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, TOKEN_TYPE, URL +""" diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 917f5f8..587d6ab 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -21,7 +21,8 @@ def create_constants_for_client(yaml_dict: dict) -> str: "# Client constants\n" f"URL = '{yaml_dict['servers'][0]['url']}'\n" "PARAM_NAME_SORT = 'sort'\n" - "PARAM_NAME_SORT_FIELD = 'sort_field'\n\n" + "PARAM_NAME_SORT_FIELD = 'sort_field'\n" + "TOKEN_TYPE = 'Bearer'\n\n" "# Logger constants\n" "LOG_FILE_NAME = 'pachca_log.log'\n" "MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB\n" From 940441d02939f226c1c60fd3b24924fa82cdba32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 17:25:34 +0300 Subject: [PATCH 252/296] =?UTF-8?q?yaml=5Fproccesor.py=20=D1=81=D1=82?= =?UTF-8?q?=D1=80.25=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20TOKEN=5FTYPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generator2/yaml_processor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 917f5f8..587d6ab 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -21,7 +21,8 @@ def create_constants_for_client(yaml_dict: dict) -> str: "# Client constants\n" f"URL = '{yaml_dict['servers'][0]['url']}'\n" "PARAM_NAME_SORT = 'sort'\n" - "PARAM_NAME_SORT_FIELD = 'sort_field'\n\n" + "PARAM_NAME_SORT_FIELD = 'sort_field'\n" + "TOKEN_TYPE = 'Bearer'\n\n" "# Logger constants\n" "LOG_FILE_NAME = 'pachca_log.log'\n" "MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB\n" From be99fc4bbf8ba240ed542bd8e096447820a623cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 18:24:53 +0300 Subject: [PATCH 253/296] finish --- src/generator1/client_servis.py | 4 +- src/generator1/generator.py | 67 ++++++++++++++++--- .../templates/endpoint_module.py.jinja | 14 ++-- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index 03e7d8f..cc2a26d 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -94,12 +94,12 @@ async def get_httpx_client(self) -> httpx.Client: async def __enter__(self) -> "AuthenticatedClient": """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() + await self.get_httpx_client().__enter__() return self async def __exit__(self, *args: Any, **kwargs: Any) -> None: """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) + await self.get_httpx_client().__exit__(*args, **kwargs) async def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": """Manually the underlying httpx.AsyncClient diff --git a/src/generator1/generator.py b/src/generator1/generator.py index 10a92e5..9164b86 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -1,6 +1,12 @@ import subprocess import sys +MIN_ARGS = 2 +COMMAND_INDEX = 1 +GENERATE_COMMAND = "generate" +INSTALL_TEST_COMMAND = "test" + + def run_command(command): """Функция для выполнения команды в терминале.""" try: @@ -22,16 +28,57 @@ def install_and_run_tests(): run_command("python pachca.py") if __name__ == "__main__": - if len(sys.argv) != 2: - print("Использование: python generator.py [generate|test]") - sys.exit(1) - - option = sys.argv[1] + if len(sys.argv) < MIN_ARGS: + print("Пример команды: python generator.py [generate|test]") + sys.exit(COMMAND_INDEX) - if option == "generate": - generate_client() - elif option == "test": - install_and_run_tests() + command = sys.argv[COMMAND_INDEX] + commands = { + GENERATE_COMMAND: generate_client, + INSTALL_TEST_COMMAND: install_and_run_tests, + } + if command in commands: + commands[command]() else: print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") - sys.exit(1) + sys.exit(COMMAND_INDEX) + + + +# import subprocess +# import sys + +# def run_command(command): +# """Функция для выполнения команды в терминале.""" +# try: +# subprocess.run(command, check=True, shell=True, text=True) +# print(f"Команда выполнена: {command}") +# except subprocess.CalledProcessError as e: +# print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") + +# def generate_client(): +# """Генерация клиента и запуск скрипта-генератора.""" +# print("Генерация клиента...") +# run_command("openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite") +# run_command("python script.py") + +# def install_and_run_tests(): +# """Установка пакета и запуск тест-запросов.""" +# print("Установка пакета и запуск тест-запросов...") +# run_command("pip install ./pachca-api-open-api-3-0-client") +# run_command("python pachca.py") + +# if __name__ == "__main__": +# if len(sys.argv) != 2: +# print("Пример команды: python generator.py [generate|test]") +# sys.exit(1) + +# option = sys.argv[1] + +# if option == "generate": +# generate_client() +# elif option == "test": +# install_and_run_tests() +# else: +# print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") +# sys.exit(1) diff --git a/src/generator1/templates/endpoint_module.py.jinja b/src/generator1/templates/endpoint_module.py.jinja index 4cc3003..69c4c0d 100644 --- a/src/generator1/templates/endpoint_module.py.jinja +++ b/src/generator1/templates/endpoint_module.py.jinja @@ -99,7 +99,7 @@ async def _build_response_{{ endpoint.name }}(self, response: httpx.Response) -> status_code=HTTPStatus(response.status_code), content=response.content, headers=response.headers, - parsed=self._parse_response_{{ endpoint.name }}(response=response), + parsed= await self._parse_response_{{ endpoint.name }}(response=response), ) @@ -109,14 +109,14 @@ async def {{ endpoint.name }}(self, {{ docstring(endpoint, return_string, is_detailed=false) | indent(4) }} self.logger.info("Начинаем создание ответа на запрос.") - kwargs = self._get_kwargs_{{ endpoint.name }}( + kwargs = await self._get_kwargs_{{ endpoint.name }}( {{ kwargs(endpoint, include_client=False) }} ) - response = await self.client.get_async_httpx_client().request( - **kwargs - ) + response = await ( + await self.client.get_async_httpx_client() + ).request(**kwargs) - return self._build_response_{{ endpoint.name }}( - response=response).parsed + return (await self._build_response_{{ endpoint.name }}( + response=response)).parsed From ee245b9ad12843bf19e76af0af9e041811c0bb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 19:11:14 +0300 Subject: [PATCH 254/296] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20Bot=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BB=D0=B0?= =?UTF-8?q?=D1=81=D1=81=D0=B0=20RequestMethods=20=D0=B2=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=20request=5Fmethods.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generator2/generator2_full/bot.py | 38 ++------------------- src/generator2/request_methods_generator.py | 36 +++++++++++-------- src/generator2/services/constants.py | 13 +++++++ 3 files changed, 36 insertions(+), 51 deletions(-) diff --git a/src/generator2/generator2_full/bot.py b/src/generator2/generator2_full/bot.py index 5a37de0..c66f838 100644 --- a/src/generator2/generator2_full/bot.py +++ b/src/generator2/generator2_full/bot.py @@ -1,44 +1,10 @@ -import importlib -import inspect -from typing import Callable - import httpx from .constants import PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, TOKEN_TYPE, URL +from .request_methods import RequestMethods -class RequestMethodsCollector(type): - - def __new__(cls, name, bases, dct): - req_methods = importlib.import_module('.request_methods', __package__) - request_methods = cls.collect_methods(req_methods) - - for name_method, method in request_methods.items(): - dct[name_method] = method - - return super( - RequestMethodsCollector, cls, - ).__new__(cls, name, bases, dct) - - @staticmethod - def collect_methods(module) -> dict[str, Callable]: - """Собирает сгенерированные функции из модуля request_methods.py""" - dict_func = {} - - for name, obj in inspect.getmembers(module): - if inspect.isfunction(obj): - dict_func[name] = obj - - if not dict_func: - raise ValueError( - f"В модуле {module.__name__} " - "отсутствуют сгенерированные функции", - ) - - return dict_func - - -class Bot(metaclass=RequestMethodsCollector): +class Bot(RequestMethods): base_url = URL token_type = TOKEN_TYPE diff --git a/src/generator2/request_methods_generator.py b/src/generator2/request_methods_generator.py index 6c9d6ad..e3e1db8 100644 --- a/src/generator2/request_methods_generator.py +++ b/src/generator2/request_methods_generator.py @@ -14,7 +14,8 @@ PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, PARAM_TYPE_KEY, PREFIX_REQUEST, PREFIX_RESPONSE, SCHEMA_SORT_ID, - SPECIFICATION_FILE_NAME, TYPE_SORT_FIELD) + SPECIFICATION_FILE_NAME, TYPE_SORT_FIELD, + TEMPLATE_CLASS_REQUEST_METHODS) def format_path_params(param_path: dict[str, Union[str, dict]]) -> str: @@ -99,13 +100,17 @@ def generate_response_handling( """Генерирует логику обработки ответа от сервера.""" response_handling = "" if name_response_scheme: - response_handling += f""" - if response.is_success: - return {name_response_scheme}.model_validate_json(response.text)""" + response_handling += ( + '\n if response.is_success:\n' + f' return {name_response_scheme}' + '.model_validate_json(response.text)' + ) if name_error_scheme: - response_handling += f""" - if response.is_client_error: - return {name_error_scheme}.model_validate_json(response.text)""" + response_handling += ( + '\n if response.is_client_error:\n' + f' return {name_error_scheme}' + '.model_validate_json(response.text)' + ) return response_handling @@ -136,20 +141,20 @@ def get_template_methods( f" -> {name_response_scheme}" if name_response_scheme else "" ) filter_params_code = ( - f"\n query_params = await self.filter_query_params" + f"\n query_params = await self.filter_query_params" f"({filter_params})" if filter_params else "" ) return f""" -async def {name_func}({function_params}){response_annotation}: - {docstring} - client = await self.get_client() - async with client: - {format_url}{filter_params_code} - {request_handling}{response_handling} - return None + async def {name_func}({function_params}){response_annotation}: + {docstring} + client = await self.get_client() + async with client: + {format_url}{filter_params_code} + {request_handling}{response_handling} + return None """ @@ -378,6 +383,7 @@ def generation_methods_request( ) as file: for module_name in import_templates: file.write(f'{module_name}\n') + file.write(TEMPLATE_CLASS_REQUEST_METHODS) for template in templates: file.write(template) diff --git a/src/generator2/services/constants.py b/src/generator2/services/constants.py index d586289..df2e3ea 100644 --- a/src/generator2/services/constants.py +++ b/src/generator2/services/constants.py @@ -41,3 +41,16 @@ LOG_FILE_NAME = 'client_generator.log' GENERATED_CLIENT_FOLDER = 'generator2_full' + +TEMPLATE_CLASS_REQUEST_METHODS = """ +class RequestMethods: + + async def get_client(self): + pass + + async def format_url(self): + pass + + async def filter_query_params(self): + pass +""" From c4e2543cf896ed5c3b7135fa50887490d3976b96 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 19:18:39 +0300 Subject: [PATCH 255/296] fix errored response log --- src/generator2/generator2_full/pachca.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index bca36f2..86cc912 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -168,7 +168,7 @@ async def run_pachca(): response_leave_chat = await pachca.leave_chat( id=created_chat.data.id ) - logger.debug(f'leave_chat: {response_leave_chat.data[0].id}') + logger.debug(f'leave_chat: {response_leave_chat}') response_get_users = await pachca.get_employees() logger.debug(f'One user from list: {response_get_users.data[0].id}') From 9861c3891e0ac1305ccb8ff3578120a1c96c93c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=91=D1=83?= =?UTF-8?q?=D1=80=D0=BC=D0=B8=D1=81=D1=82=D1=80=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 19:39:37 +0300 Subject: [PATCH 256/296] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/generator2/generator2_full/constants.py | 10 -- .../models/models_reqBod_createChat.py | 28 ----- .../models/models_reqBod_createMessage.py | 66 ----------- .../models/models_reqBod_createTask.py | 45 -------- .../models/models_reqBod_editMessage.py | 46 -------- .../models/models_reqBod_getDirectUrl.py | 37 ------ .../models_reqBod_postMembersToChats.py | 14 --- .../models_reqBod_postMessageReactions.py | 7 -- .../models/models_reqBod_postTagsToChats.py | 10 -- .../models/models_reqBod_putStatus.py | 19 ---- .../models_response_createChatpost201.py | 43 ------- .../models_response_createChatpost400.py | 30 ----- .../models_response_createChatpost422.py | 30 ----- .../models_response_createMessagepost201.py | 104 ----------------- .../models_response_createMessagepost400.py | 30 ----- .../models_response_createTaskpost201.py | 66 ----------- .../models_response_createTaskpost400.py | 30 ----- .../models_response_createThreadpost200.py | 23 ---- .../models_response_createThreadpost400.py | 30 ----- ...esponse_deleteMessageReactionsdelete400.py | 30 ----- .../models_response_editMessageput200.py | 104 ----------------- .../models_response_editMessageput400.py | 30 ----- .../models/models_response_getChatget200.py | 43 ------- .../models/models_response_getChatget400.py | 30 ----- .../models/models_response_getChatsget200.py | 45 -------- .../models/models_response_getChatsget400.py | 30 ----- .../models/models_response_getChatsget422.py | 30 ----- .../models_response_getCommonMethodsget200.py | 23 ---- .../models_response_getCommonMethodsget400.py | 30 ----- .../models_response_getEmployeeget200.py | 90 --------------- .../models_response_getEmployeeget400.py | 30 ----- .../models_response_getEmployeesget200.py | 92 --------------- .../models_response_getListMessageget200.py | 106 ------------------ .../models_response_getListMessageget400.py | 30 ----- ...dels_response_getMessageReactionsget200.py | 20 ---- ...dels_response_getMessageReactionsget400.py | 30 ----- .../models_response_getMessageget200.py | 104 ----------------- .../models_response_getMessageget400.py | 30 ----- .../models/models_response_getStatusget200.py | 19 ---- .../models/models_response_getTagget200.py | 18 --- .../models/models_response_getTagget400.py | 30 ----- .../models_response_getTagsEmployeesget200.py | 68 ----------- .../models_response_getTagsEmployeesget400.py | 30 ----- .../models/models_response_getTagsget200.py | 17 --- .../models/models_response_getTagsget400.py | 30 ----- .../models_response_getUploadspost200.py | 39 ------- .../models_response_leaveChatdelete400.py | 30 ----- ...dels_response_postMembersToChatspost400.py | 30 ----- ...dels_response_postMembersToChatspost422.py | 30 ----- ...ls_response_postMessageReactionspost400.py | 30 ----- .../models_response_postTagsToChatspost400.py | 30 ----- .../models_response_postTagsToChatspost422.py | 30 ----- .../models/models_response_putStatusput201.py | 19 ---- .../models/models_response_putStatusput400.py | 30 ----- .../generator2_full/request_methods.py | 0 src/generator2/generator_starter.py | 6 +- ...erator.py => request_methods_generator.py} | 4 +- src/generator2/services/constants.py | 1 - 58 files changed, 5 insertions(+), 2081 deletions(-) delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createChat.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createMessage.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createTask.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_editMessage.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_putStatus.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost200.py delete mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py delete mode 100644 src/generator2/generator2_full/models/models_response_editMessageput200.py delete mode 100644 src/generator2/generator2_full/models/models_response_editMessageput400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget422.py delete mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeesget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getStatusget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getUploadspost200.py delete mode 100644 src/generator2/generator2_full/models/models_response_leaveChatdelete400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_putStatusput201.py delete mode 100644 src/generator2/generator2_full/models/models_response_putStatusput400.py create mode 100644 src/generator2/generator2_full/request_methods.py rename src/generator2/{class_bot_generator.py => request_methods_generator.py} (99%) diff --git a/src/generator2/generator2_full/constants.py b/src/generator2/generator2_full/constants.py index 7055256..e69de29 100644 --- a/src/generator2/generator2_full/constants.py +++ b/src/generator2/generator2_full/constants.py @@ -1,10 +0,0 @@ -# Client constants -URL = 'https://api.pachca.com/api/shared/v1' -PARAM_NAME_SORT = 'sort' -PARAM_NAME_SORT_FIELD = 'sort_field' -TOKEN_TYPE = 'Bearer' - -# Logger constants -LOG_FILE_NAME = 'pachca_log.log' -MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB -BACKUP_COUNT = 3 diff --git a/src/generator2/generator2_full/models/models_reqBod_createChat.py b/src/generator2/generator2_full/models/models_reqBod_createChat.py deleted file mode 100644 index 089e9c2..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createChat.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Chat(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - - -class Createchat(BaseModel): - chat: Optional[Chat] = Field( - None, - description="Собранный объект параметров создаваемой беседы или канала", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createMessage.py b/src/generator2/generator2_full/models/models_reqBod_createMessage.py deleted file mode 100644 index a6280ed..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createMessage.py +++ /dev/null @@ -1,66 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - size: int = Field( - ..., description="Размер файла в байтах, отображаемый пользователю", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Message(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - skip_invite_mentions: Optional[bool] = Field( - None, description="No docstring provided", - ) - link_preview: Optional[bool] = Field( - None, description="No docstring provided", - ) - - -class Createmessage(BaseModel): - message: Optional[Message] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createTask.py b/src/generator2/generator2_full/models/models_reqBod_createTask.py deleted file mode 100644 index ce503e3..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createTask.py +++ /dev/null @@ -1,45 +0,0 @@ -from enum import IntEnum, StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - value: Optional[str] = Field(None, description="Значение поля") - - -class enum_kind(StrEnum): - call = "call" - meeting = "meeting" - reminder = "reminder" - event = "event" - email = "email" - - -class enum_priority(IntEnum): - priority_1 = 1 - priority_2 = 2 - priority_3 = 3 - - -class Task(BaseModel): - kind: enum_kind = Field(..., description="Тип напоминания") - content: str = Field(..., description="Описание напоминания") - due_at: str = Field( - ..., description="Срок выполнения напоминания (ISO-8601)", - ) - priority: Optional[enum_priority] = Field( - None, - description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", - ) - performer_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов пользователей", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="No docstring provided", - ) - - -class Createtask(BaseModel): - task: Optional[Task] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_reqBod_editMessage.py b/src/generator2/generator2_full/models/models_reqBod_editMessage.py deleted file mode 100644 index 8db9faf..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_editMessage.py +++ /dev/null @@ -1,46 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - size: int = Field( - ..., description="Размер файла в байтах, отображаемый пользователю", - ) - - -class Message(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - - -class Editmessage(BaseModel): - message: Optional[Message] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py deleted file mode 100644 index a4f35e7..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Getdirecturl(BaseModel): - Content_Disposition: Optional[str] = Field( - None, - description="Используемый заголовок", - alilas="Content-Disposition", - ) - acl: Optional[str] = Field(None, description="Уровень безопасности") - policy: Optional[str] = Field( - None, description="Уникальный policy для загрузки файла", - ) - x_amz_credential: Optional[str] = Field( - None, - description="x-amz-credential для загрузки файла", - alilas="x-amz-credential", - ) - x_amz_algorithm: Optional[str] = Field( - None, description="Используемый алгоритм", alilas="x-amz-algorithm", - ) - x_amz_date: Optional[str] = Field( - None, - description="Уникальный x-amz-date для загрузки файла", - alilas="x-amz-date", - ) - x_amz_signature: Optional[str] = Field( - None, - description="Уникальная подпись для загрузки файла", - alilas="x-amz-signature", - ) - key: Optional[str] = Field( - None, description="Уникальный ключ для загрузки файла", - ) - file: Optional[str] = Field(None, description="Адрес для загрузки файла") diff --git a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py deleted file mode 100644 index 59b7182..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Postmemberstochats(BaseModel): - member_ids: List[int] = Field( - ..., - description="Массив идентификаторов пользователей, которые станут участниками", - ) - silent: Optional[bool] = Field( - None, - description="Не создавать в чате системное сообщение о добавлении участника", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py deleted file mode 100644 index ba69294..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py +++ /dev/null @@ -1,7 +0,0 @@ -from pydantic import BaseModel, Field - - -class Postmessagereactions(BaseModel): - code: str = Field( - ..., description="Emoji в строковом формате для добавления реакции.", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py deleted file mode 100644 index f935dd3..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List - -from pydantic import BaseModel, Field - - -class Posttagstochats(BaseModel): - group_tag_ids: List[int] = Field( - ..., - description="Массив идентификаторов тегов, которые станут участниками", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_putStatus.py b/src/generator2/generator2_full/models/models_reqBod_putStatus.py deleted file mode 100644 index 0e19d8f..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_putStatus.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class Putstatus(BaseModel): - status: Optional[Status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost201.py b/src/generator2/generator2_full/models/models_response_createChatpost201.py deleted file mode 100644 index 289211b..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost201.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseCreatechatPost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createChatpost400.py b/src/generator2/generator2_full/models/models_response_createChatpost400.py deleted file mode 100644 index 3d5be37..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatechatPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost422.py b/src/generator2/generator2_full/models/models_response_createChatpost422.py deleted file mode 100644 index 9ee79aa..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatechatPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost201.py b/src/generator2/generator2_full/models/models_response_createMessagepost201.py deleted file mode 100644 index a7da269..0000000 --- a/src/generator2/generator2_full/models/models_response_createMessagepost201.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseCreatemessagePost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost400.py b/src/generator2/generator2_full/models/models_response_createMessagepost400.py deleted file mode 100644 index b484245..0000000 --- a/src/generator2/generator2_full/models/models_response_createMessagepost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatemessagePost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost201.py b/src/generator2/generator2_full/models/models_response_createTaskpost201.py deleted file mode 100644 index 749ca91..0000000 --- a/src/generator2/generator2_full/models/models_response_createTaskpost201.py +++ /dev/null @@ -1,66 +0,0 @@ -from enum import IntEnum, StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - value: Optional[str] = Field(None, description="Значение поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - - -class enum_kind(StrEnum): - call = "call" - meeting = "meeting" - reminder = "reminder" - event = "event" - email = "email" - - -class enum_priority(IntEnum): - priority_1 = 1 - priority_2 = 2 - priority_3 = 3 - - -class Data(BaseModel): - kind: enum_kind = Field(..., description="Тип напоминания") - content: str = Field(..., description="Описание напоминания") - due_at: str = Field( - ..., description="Срок выполнения напоминания (ISO-8601)", - ) - priority: Optional[enum_priority] = Field( - None, - description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", - ) - performer_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов пользователей", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="No docstring provided", - ) - id: Optional[int] = Field( - None, description="Идентификатор созданного напоминания", - ) - user_id: Optional[int] = Field( - None, description="Идентификатор пользователя-создателя", - ) - status: Optional[str] = Field(None, description="Статус напоминания") - created_at: Optional[str] = Field( - None, description="Дата и время создания", - ) - - -class ResponseCreatetaskPost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost400.py b/src/generator2/generator2_full/models/models_response_createTaskpost400.py deleted file mode 100644 index 7b83d43..0000000 --- a/src/generator2/generator2_full/models/models_response_createTaskpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatetaskPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost200.py b/src/generator2/generator2_full/models/models_response_createThreadpost200.py deleted file mode 100644 index 93e2199..0000000 --- a/src/generator2/generator2_full/models/models_response_createThreadpost200.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред.", - ) - message_chat_id: Optional[int] = Field( - None, description="Идентификатор чата сообщения.", - ) - updated_at: Optional[str] = Field( - None, - description="Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", - ) - - -class ResponseCreatethreadPost200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost400.py b/src/generator2/generator2_full/models/models_response_createThreadpost400.py deleted file mode 100644 index aab3648..0000000 --- a/src/generator2/generator2_full/models/models_response_createThreadpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatethreadPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py deleted file mode 100644 index c80757d..0000000 --- a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseDeletemessagereactionsDelete400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_editMessageput200.py b/src/generator2/generator2_full/models/models_response_editMessageput200.py deleted file mode 100644 index 2daa577..0000000 --- a/src/generator2/generator2_full/models/models_response_editMessageput200.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseEditmessagePut200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_editMessageput400.py b/src/generator2/generator2_full/models/models_response_editMessageput400.py deleted file mode 100644 index cb7e60d..0000000 --- a/src/generator2/generator2_full/models/models_response_editMessageput400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseEditmessagePut400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatget200.py b/src/generator2/generator2_full/models/models_response_getChatget200.py deleted file mode 100644 index 26c9d0a..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatget200.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseGetchatGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getChatget400.py b/src/generator2/generator2_full/models/models_response_getChatget400.py deleted file mode 100644 index 5cf12e6..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget200.py b/src/generator2/generator2_full/models/models_response_getChatsget200.py deleted file mode 100644 index 68c2eec..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget200.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseGetchatsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget400.py b/src/generator2/generator2_full/models/models_response_getChatsget400.py deleted file mode 100644 index 0893c6b..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget422.py b/src/generator2/generator2_full/models/models_response_getChatsget422.py deleted file mode 100644 index 89c7937..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatsGet422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py deleted file mode 100644 index 9c132b3..0000000 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py +++ /dev/null @@ -1,23 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Название поля") - name: Optional[str] = Field(None, description="Идентификатор поля") - data_type: Optional[enum_data_type] = Field(None, description="тип поля") - - -class ResponseGetcommonmethodsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py deleted file mode 100644 index f2ae8ba..0000000 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetcommonmethodsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py deleted file mode 100644 index a798652..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py +++ /dev/null @@ -1,90 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class User_status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - user_status: Optional[User_status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) - title: Optional[str] = Field(None, description="Должность") - created_at: Optional[str] = Field( - None, - description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - time_zone: Optional[str] = Field( - None, description="Часовой пояс пользователя", - ) - image_url: Optional[str] = Field( - None, description="Ссылка на скачивание аватарки", - ) - - -class ResponseGetemployeeGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py deleted file mode 100644 index a22237a..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetemployeeGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py deleted file mode 100644 index 6f24174..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py +++ /dev/null @@ -1,92 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class User_status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - user_status: Optional[User_status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) - title: Optional[str] = Field(None, description="Должность") - created_at: Optional[str] = Field( - None, - description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - time_zone: Optional[str] = Field( - None, description="Часовой пояс пользователя", - ) - image_url: Optional[str] = Field( - None, description="Ссылка на скачивание аватарки", - ) - - -class ResponseGetemployeesGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget200.py b/src/generator2/generator2_full/models/models_response_getListMessageget200.py deleted file mode 100644 index c187528..0000000 --- a/src/generator2/generator2_full/models/models_response_getListMessageget200.py +++ /dev/null @@ -1,106 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseGetlistmessageGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget400.py b/src/generator2/generator2_full/models/models_response_getListMessageget400.py deleted file mode 100644 index 9bc441d..0000000 --- a/src/generator2/generator2_full/models/models_response_getListMessageget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetlistmessageGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py deleted file mode 100644 index ce9da6a..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - user_id: Optional[int] = Field( - None, description="Идентификатор пользователя, оставившего реакцию.", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", - ) - code: Optional[str] = Field(None, description="Emoji символ реакции.") - - -class ResponseGetmessagereactionsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py deleted file mode 100644 index 369fcdf..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetmessagereactionsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageget200.py b/src/generator2/generator2_full/models/models_response_getMessageget200.py deleted file mode 100644 index 92d3d71..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageget200.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseGetmessageGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getMessageget400.py b/src/generator2/generator2_full/models/models_response_getMessageget400.py deleted file mode 100644 index 9c51172..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetmessageGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getStatusget200.py b/src/generator2/generator2_full/models/models_response_getStatusget200.py deleted file mode 100644 index 0d09a11..0000000 --- a/src/generator2/generator2_full/models/models_response_getStatusget200.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class ResponseGetstatusGet200(BaseModel): - data: Optional[Data] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget200.py b/src/generator2/generator2_full/models/models_response_getTagget200.py deleted file mode 100644 index ef7a650..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagget200.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор тега") - name: Optional[str] = Field(None, description="Название тега") - users_count: Optional[int] = Field( - None, description="Количество сотрудников, которые имеют этот тег", - ) - - -class ResponseGettagGet200(BaseModel): - data: Optional[Data] = Field( - None, - description="Для получения тега вам необходимо знать его id и указать его в URL запроса.", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget400.py b/src/generator2/generator2_full/models/models_response_getTagget400.py deleted file mode 100644 index a3b9fe0..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py deleted file mode 100644 index d835b3a..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py +++ /dev/null @@ -1,68 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - - -class ResponseGettagsemployeesGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py deleted file mode 100644 index a7c67de..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagsemployeesGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget200.py b/src/generator2/generator2_full/models/models_response_getTagsget200.py deleted file mode 100644 index a6f0b4b..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsget200.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор тега") - name: Optional[str] = Field(None, description="Название тега") - users_count: Optional[int] = Field( - None, description="Количество сотрудников, которые имеют этот тег", - ) - - -class ResponseGettagsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget400.py b/src/generator2/generator2_full/models/models_response_getTagsget400.py deleted file mode 100644 index 0015a61..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getUploadspost200.py b/src/generator2/generator2_full/models/models_response_getUploadspost200.py deleted file mode 100644 index 0d31122..0000000 --- a/src/generator2/generator2_full/models/models_response_getUploadspost200.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class ResponseGetuploadsPost200(BaseModel): - Content_Disposition: Optional[str] = Field( - None, - description="Используемый заголовок", - alilas="Content-Disposition", - ) - acl: Optional[str] = Field(None, description="Уровень безопасности") - policy: Optional[str] = Field( - None, description="Уникальный policy для загрузки файла", - ) - x_amz_credential: Optional[str] = Field( - None, - description="x-amz-credential для загрузки файла", - alilas="x-amz-credential", - ) - x_amz_algorithm: Optional[str] = Field( - None, description="Используемый алгоритм", alilas="x-amz-algorithm", - ) - x_amz_date: Optional[str] = Field( - None, - description="Уникальный x-amz-date для загрузки файла", - alilas="x-amz-date", - ) - x_amz_signature: Optional[str] = Field( - None, - description="Уникальная подпись для загрузки файла", - alilas="x-amz-signature", - ) - key: Optional[str] = Field( - None, description="Уникальный ключ для загрузки файла", - ) - direct_url: Optional[str] = Field( - None, description="Адрес для загрузки файла", - ) diff --git a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py deleted file mode 100644 index 3e430a1..0000000 --- a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseLeavechatDelete400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py deleted file mode 100644 index 5dd1dbd..0000000 --- a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmemberstochatsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py deleted file mode 100644 index bdf933f..0000000 --- a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmemberstochatsPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py deleted file mode 100644 index 0d305f2..0000000 --- a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmessagereactionsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py deleted file mode 100644 index e0385a7..0000000 --- a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePosttagstochatsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py deleted file mode 100644 index 8b157bf..0000000 --- a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePosttagstochatsPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput201.py b/src/generator2/generator2_full/models/models_response_putStatusput201.py deleted file mode 100644 index db4d1ca..0000000 --- a/src/generator2/generator2_full/models/models_response_putStatusput201.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class ResponsePutstatusPut201(BaseModel): - data: Optional[Data] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput400.py b/src/generator2/generator2_full/models/models_response_putStatusput400.py deleted file mode 100644 index 74a54e1..0000000 --- a/src/generator2/generator2_full/models/models_response_putStatusput400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePutstatusPut400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator2/generator_starter.py b/src/generator2/generator_starter.py index 0f9890e..192fe78 100644 --- a/src/generator2/generator_starter.py +++ b/src/generator2/generator_starter.py @@ -3,7 +3,7 @@ from .services.constants import GENERATED_CLIENT_FOLDER from .services.logger_setup import setup_logging -from .class_bot_generator import generate +from .request_methods_generator import generate from .yaml_processor import process_endpoints @@ -34,7 +34,7 @@ def generate_client(): subprocess.run( [ 'black', - f'{dir_path}/bot.py', + f'{dir_path}/request_methods.py', '--line-length', '79' ], @@ -54,7 +54,7 @@ def generate_client(): [ 'ruff', 'check', - f'{dir_path}/bot.py', + f'{dir_path}/request_methods.py', '--fix', '--silent' ] diff --git a/src/generator2/class_bot_generator.py b/src/generator2/request_methods_generator.py similarity index 99% rename from src/generator2/class_bot_generator.py rename to src/generator2/request_methods_generator.py index 9cee737..096ce6e 100644 --- a/src/generator2/class_bot_generator.py +++ b/src/generator2/request_methods_generator.py @@ -376,14 +376,14 @@ def get_obj_openapi_spec( def generation_class_bot( templates: list, import_templates: list, - file=f'./{__package__}/{GENERATED_CLIENT_FOLDER}/bot.py', + file=f'./{__package__}/{GENERATED_CLIENT_FOLDER}/request_methods.py', ): with open( file, 'w', encoding='utf-8', ) as file: - file.write(f'{TEMPLATE_IMPORT_FOR_CLASS_BOT}') for module_name in import_templates: file.write(f'{module_name}\n') + file.write(f'{TEMPLATE_CLASS_REQUEST_METHODS}') for template in templates: file.write(template) diff --git a/src/generator2/services/constants.py b/src/generator2/services/constants.py index 0ae9525..df2e3ea 100644 --- a/src/generator2/services/constants.py +++ b/src/generator2/services/constants.py @@ -53,5 +53,4 @@ async def format_url(self): async def filter_query_params(self): pass ->>>>>>> bugfix/generator2/1-2 """ From f09ad098324052d017b8656d1416983c8df828e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D0=BE=D1=80=D0=B0?= Date: Mon, 13 Jan 2025 20:21:03 +0300 Subject: [PATCH 257/296] testing/all_endpoints/generator1 20:20 20250113 --- src/generator1/pachca.py | 61 +++++++++++++++++++++++++++++++++++----- src/generator1/script.py | 1 + 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 735ad1e..4f527a8 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -19,7 +19,8 @@ CreateTaskBody, ) from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody + CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody, + GroupTag, MembersChat ) from pachca_api_open_api_3_0_client.models.base_chat import BaseChat from pachca_api_open_api_3_0_client.models.code_reaction import ( @@ -37,6 +38,7 @@ 'pachca_testresults.log' ) + async def main() -> None: """ Функция теста эндпоинтов """ @@ -86,7 +88,6 @@ async def main() -> None: pachca.editMessage( id=message_response.data.id, body=edit_message_body) ) - # подготовка запроса на добавление реакции к сообщению --> post_reactions = CodeReaction(code='😭') @@ -99,10 +100,14 @@ async def main() -> None: # подготовка запроса на получение списка реакций к сообщению --> # <-- # запрос на получение списка реакций - getMessageReactions = await pachca.getMessageReactions(id=message_response.data.id) + getMessageReactions = await pachca.getMessageReactions( + id=message_response.data.id + ) # запрос на удаление реакции - deleteMessageReactions = await pachca.deleteMessageReactions(id=message_response.data.id, code='😭') + deleteMessageReactions = await pachca.deleteMessageReactions( + id=message_response.data.id, code='😭' + ) # подготовка запроса на создание напоминания --> create_body_task = CreateTaskBodyTask( @@ -113,13 +118,25 @@ async def main() -> None: body_task = CreateTaskBody(task=create_body_task) # <-- # запрос на создание напоминания - createtaskbody = await asyncio.create_task(pachca.createTask(body=body_task)) + createtaskbody = await asyncio.create_task( + pachca.createTask(body=body_task) + ) # запрос на получения списка пользователей users_response = await asyncio.create_task(pachca.getEmployees()) # запрос на получение информации о пользователе - getEmployee = await asyncio.create_task(pachca.getEmployee(id=users_response.data[0].id)) + getEmployee = await asyncio.create_task( + pachca.getEmployee(id=users_response.data[0].id) + ) + + # подготовка запроса на добавление участника --> + chats_body = MembersChat(member_ids=[users_response.data[0].id]) + # <-- + # запрос на добавление участника в беседу + postMembersToChats = await asyncio.create_task(pachca.postMembersToChats( + id=chat_response.data.id, body=chats_body) + ) # подготовка запроса на добавление статуса --> query_status = QueryStatusStatus( @@ -132,7 +149,7 @@ async def main() -> None: putStatus = await asyncio.create_task(pachca.putStatus(body=query_status)) # запрос на получение информации о своем статусе - getStatus = await asyncio.create_task(pachca.getStatus()) + getStatus = await asyncio.create_task(pachca.getStatus()) # запрос на удаление статуса delStatus = await asyncio.create_task(pachca.delStatus()) @@ -140,6 +157,26 @@ async def main() -> None: # запрос на получение тегов сотрудников getTags = await asyncio.create_task(pachca.getTags()) + if len(getTags.data) > 0: + tag_id = getTags.data[0].id + else: + tag_id = 0 + # запрос получение информации о теге + getTag = await asyncio.create_task(pachca.getTag(id=tag_id)) + + # запрос получение информации о теге участников + getTagsEmployees = await asyncio.create_task( + pachca.getTagsEmployees(id=tag_id) + ) + + # подготовка запроса на добавление участника --> + tags_body = GroupTag(group_tag_ids=[tag_id]) + # <-- + # запрос на добавление тегов в состав участников беседы или канала + postTagsToChats = await asyncio.create_task( + pachca.postTagsToChats(id=chat_response.data.id, body=tags_body) + ) + # запрос на получение списка актуальных полей сущности getCommonMethods = await asyncio.create_task( pachca.getCommonMethods(entity_type='User')) @@ -147,6 +184,11 @@ async def main() -> None: # запрос получения подписи и ключа для загрузки файла getUploads = await asyncio.create_task(pachca.getUploads()) + # запрос исключение участника из беседы + leaveChat = await asyncio.create_task( + pachca.leaveChat(id=chat_response.data.id) + ) + logger.debug(await pachca.getUploads()) for task in ( @@ -165,12 +207,17 @@ async def main() -> None: createtaskbody, users_response, getEmployee, + postMembersToChats, putStatus, getStatus, delStatus, getTags, + getTag, + getTagsEmployees, + postTagsToChats, getCommonMethods, getUploads, + leaveChat, ): result = task diff --git a/src/generator1/script.py b/src/generator1/script.py index f6c14a6..49f66d8 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -151,6 +151,7 @@ def get_base_url_from_yaml(openapi_yaml): "79", ], check=True, + shell=True, ) subprocess.run( [ From ed53855102d5f1f35ae7ec65c4f3ff0164a05763 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 20:54:16 +0300 Subject: [PATCH 258/296] add missing await --- src/generator2/generator2_full/pachca.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 86cc912..3f84f2e 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -200,15 +200,15 @@ async def run_pachca(): logger.debug(f'del_status: {response_del_status}') # Получения подписи и ключа для загрузки файла - response_get_uploads = pachca.get_uploads() + response_get_uploads = await pachca.get_uploads() logger.debug(f'del_status: {response_get_uploads}') - response_get_tags_employees = pachca.get_tags_employees( + response_get_tags_employees = await pachca.get_tags_employees( id=1234 ) logger.debug(f'get_tags_employees: {response_get_tags_employees}') - response_get_tag = pachca.get_tag( + response_get_tag = await pachca.get_tag( id=1234 ) logger.debug(f'get_tag: {response_get_tag}') From f004a81c5db93f03356b68d32cc2fff15a9e797e Mon Sep 17 00:00:00 2001 From: AlexG <150595546+MrAlexg82@users.noreply.github.com> Date: Mon, 13 Jan 2025 21:01:21 +0300 Subject: [PATCH 259/296] Update openapi.yaml 21:01 20250113 --- src/generator1/openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml index 0f96d4a..c947ca3 100644 --- a/src/generator1/openapi.yaml +++ b/src/generator1/openapi.yaml @@ -916,7 +916,7 @@ paths: schema: type: integer responses: - '200': + '204': description: При безошибочном выполнении запроса тело ответа отсутствуе '400': description: Пояснения ошибки @@ -2362,4 +2362,4 @@ components: type: http scheme: bearer security: - - bearerAuth: [] \ No newline at end of file + - bearerAuth: [] From 61afabf9273862e875582336cae516f57bb5ca46 Mon Sep 17 00:00:00 2001 From: AlexG <150595546+MrAlexg82@users.noreply.github.com> Date: Mon, 13 Jan 2025 21:02:24 +0300 Subject: [PATCH 260/296] Update openapi.yaml 21:03 20250113 --- src/generator1/openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml index c947ca3..939326f 100644 --- a/src/generator1/openapi.yaml +++ b/src/generator1/openapi.yaml @@ -752,7 +752,7 @@ paths: schema: $ref: '#/components/schemas/MembersChat' responses: - '201': + '204': description: Пользователи добавлены '400': description: Пояснения ошибки @@ -839,7 +839,7 @@ paths: schema: $ref: '#/components/schemas/GroupTag' responses: - '201': + '204': description: Тег(и) добавлен(ы) '400': description: Пояснения ошибки From 232b8e0847029f81beb70c7eb8a3ae3876b812a3 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 21:03:45 +0300 Subject: [PATCH 261/296] place client log into generator2 directory --- src/generator2/generator2_full/logger_setup.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/generator2/generator2_full/logger_setup.py b/src/generator2/generator2_full/logger_setup.py index 814f142..bf6f28d 100644 --- a/src/generator2/generator2_full/logger_setup.py +++ b/src/generator2/generator2_full/logger_setup.py @@ -1,14 +1,17 @@ import logging from logging.handlers import RotatingFileHandler +import os +from pathlib import Path from .constants import BACKUP_COUNT, LOG_FILE_NAME, MAX_FILE_SIZE - def setup_logging(logger_name: str) -> logging.Logger: logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) file_handler = RotatingFileHandler( - LOG_FILE_NAME, maxBytes=MAX_FILE_SIZE, + Path(os.path.dirname(os.path.abspath( + __file__))).parent / LOG_FILE_NAME, + maxBytes=MAX_FILE_SIZE, backupCount=BACKUP_COUNT, encoding='utf-8' ) From c08289040155a35801aa5b22ddca1001b9576c91 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 13 Jan 2025 21:31:07 +0300 Subject: [PATCH 262/296] fixed change --- src/generator2/README.md | 6 - src/generator2/generator2_full/pachca.py | 6 +- .../generator2_full/request_methods.py | 608 ++++++++++++++++++ 3 files changed, 609 insertions(+), 11 deletions(-) diff --git a/src/generator2/README.md b/src/generator2/README.md index 5789f6d..68b129b 100644 --- a/src/generator2/README.md +++ b/src/generator2/README.md @@ -30,9 +30,3 @@ python -m generator2.generator_starter ``` python -m generator2.generator2_full.pachca ``` - -ИЛИ перейти в generator2 ```cd generator2``` и запустить модуль - -``` -python -m generator2_full.pachca -``` \ No newline at end of file diff --git a/src/generator2/generator2_full/pachca.py b/src/generator2/generator2_full/pachca.py index 3f84f2e..16b35b2 100644 --- a/src/generator2/generator2_full/pachca.py +++ b/src/generator2/generator2_full/pachca.py @@ -27,11 +27,7 @@ "(что на 10% больше, чем в прошлое воскресенье)"), )) async def run_pachca(): - # logger.debug(f'get_employee', await pachca.get_employee(id=515190), sep='\n',end='\n'+ '*'*60 + '\n') - # logger.debug(f'get_employees', await pachca.get_employees(), sep='\n',end='\n'+ '*'*60 + '\n') - # logger.debug(f'get_chats', await pachca.get_chats(per=2), sep='\n',end='\n'+ '*'*60 + '\n') - # message = await pachca.create_message(data=message_test) - # logger.debug(message, sep='\n',end='\n'+ '*'*60 + '\n') + # Получение common methods logger.debug(f'get_common_methods: {await pachca.get_common_methods()}') # Создание беседы. diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py index e69de29..04e6a41 100644 --- a/src/generator2/generator2_full/request_methods.py +++ b/src/generator2/generator2_full/request_methods.py @@ -0,0 +1,608 @@ +from .models.models_reqBod_createChat import Createchat +from .models.models_reqBod_createMessage import Createmessage +from .models.models_reqBod_createTask import Createtask +from .models.models_reqBod_editMessage import Editmessage +from .models.models_reqBod_getDirectUrl import Getdirecturl +from .models.models_reqBod_postMembersToChats import Postmemberstochats +from .models.models_reqBod_postMessageReactions import Postmessagereactions +from .models.models_reqBod_postTagsToChats import Posttagstochats +from .models.models_reqBod_putStatus import Putstatus +from .models.models_response_createChatpost201 import ResponseCreatechatPost201 +from .models.models_response_createChatpost422 import ResponseCreatechatPost422 +from .models.models_response_createMessagepost201 import ( + ResponseCreatemessagePost201, +) +from .models.models_response_createMessagepost400 import ( + ResponseCreatemessagePost400, +) +from .models.models_response_createTaskpost201 import ResponseCreatetaskPost201 +from .models.models_response_createTaskpost400 import ResponseCreatetaskPost400 +from .models.models_response_createThreadpost200 import ( + ResponseCreatethreadPost200, +) +from .models.models_response_createThreadpost400 import ( + ResponseCreatethreadPost400, +) +from .models.models_response_deleteMessageReactionsdelete400 import ( + ResponseDeletemessagereactionsDelete400, +) +from .models.models_response_editMessageput200 import ResponseEditmessagePut200 +from .models.models_response_editMessageput400 import ResponseEditmessagePut400 +from .models.models_response_getChatget200 import ResponseGetchatGet200 +from .models.models_response_getChatget400 import ResponseGetchatGet400 +from .models.models_response_getChatsget200 import ResponseGetchatsGet200 +from .models.models_response_getChatsget422 import ResponseGetchatsGet422 +from .models.models_response_getCommonMethodsget200 import ( + ResponseGetcommonmethodsGet200, +) +from .models.models_response_getCommonMethodsget400 import ( + ResponseGetcommonmethodsGet400, +) +from .models.models_response_getEmployeeget200 import ResponseGetemployeeGet200 +from .models.models_response_getEmployeeget400 import ResponseGetemployeeGet400 +from .models.models_response_getEmployeesget200 import ( + ResponseGetemployeesGet200, +) +from .models.models_response_getListMessageget200 import ( + ResponseGetlistmessageGet200, +) +from .models.models_response_getListMessageget400 import ( + ResponseGetlistmessageGet400, +) +from .models.models_response_getMessageReactionsget200 import ( + ResponseGetmessagereactionsGet200, +) +from .models.models_response_getMessageReactionsget400 import ( + ResponseGetmessagereactionsGet400, +) +from .models.models_response_getMessageget200 import ResponseGetmessageGet200 +from .models.models_response_getMessageget400 import ResponseGetmessageGet400 +from .models.models_response_getStatusget200 import ResponseGetstatusGet200 +from .models.models_response_getTagget200 import ResponseGettagGet200 +from .models.models_response_getTagget400 import ResponseGettagGet400 +from .models.models_response_getTagsEmployeesget200 import ( + ResponseGettagsemployeesGet200, +) +from .models.models_response_getTagsEmployeesget400 import ( + ResponseGettagsemployeesGet400, +) +from .models.models_response_getTagsget200 import ResponseGettagsGet200 +from .models.models_response_getTagsget400 import ResponseGettagsGet400 +from .models.models_response_getUploadspost200 import ResponseGetuploadsPost200 +from .models.models_response_leaveChatdelete400 import ( + ResponseLeavechatDelete400, +) +from .models.models_response_postMembersToChatspost422 import ( + ResponsePostmemberstochatsPost422, +) +from .models.models_response_postMessageReactionspost400 import ( + ResponsePostmessagereactionsPost400, +) +from .models.models_response_postTagsToChatspost422 import ( + ResponsePosttagstochatsPost422, +) +from .models.models_response_putStatusput201 import ResponsePutstatusPut201 +from .models.models_response_putStatusput400 import ResponsePutstatusPut400 + + +async def get_common_methods( + self, entity_type: str = None, +) -> ResponseGetcommonmethodsGet200: + """получение списка актульных полей сущности + + Метод для получения актуального списка дополнительных полей участников и + напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в + URL (например, /custom_properties?entity_type=User) + """ + client = await self.get_client() + async with client: + url = "/custom_properties" + query_params = self.filter_query_params(entity_type=entity_type) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetcommonmethodsGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetcommonmethodsGet400.model_validate_json( + response.text, + ) + return None + + +async def get_uploads(self) -> ResponseGetuploadsPost200: + """получения подписи и ключа для загрузки файла + + Данный метод необходимо использовать для загрузки каждого файла. Данный метод + позволяет получить уникальный набор параметров для загрузки файла. Параметры + запроса отсутствуют. + """ + client = await self.get_client() + async with client: + url = "/uploads" + response = await client.post(url) + if response.is_success: + return ResponseGetuploadsPost200.model_validate_json(response.text) + return None + + +async def get_direct_url(self, data: Getdirecturl): + """(полученный в ответе на запрос /uploads) загрузка файла + + Данный метод не требует авторизации. Получив все параметры, вам необходимо + сделать POST запрос в формате multipart/form-data на адрес, который был указан + в поле direct_url, отправив полученные параметры и сам файл. + """ + client = await self.get_client() + async with client: + url = "/direct_url" + response = await client.post(url, json=data.model_dump()) + return + + +async def get_employees( + self, per: int = None, page: int = None, query: str = None, +) -> ResponseGetemployeesGet200: + """получение актуального списка всех сотрудников компании + + Метод для получения актуального списка сотрудников вашей компании. Тело запроса + отсутствует, параметры передаются в URL (например, + /users?per=50&page=2&query=example.com) + """ + client = await self.get_client() + async with client: + url = "/users" + query_params = self.filter_query_params( + per=per, page=page, query=query, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetemployeesGet200.model_validate_json( + response.text, + ) + return None + + +async def get_employee(self, id: int) -> ResponseGetemployeeGet200: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. Для получения сотрудника вам + необходимо знать его id и указать его в URL запроса. + """ + client = await self.get_client() + async with client: + url = self.format_url("/users/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGetemployeeGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGetemployeeGet400.model_validate_json(response.text) + return None + + +async def get_status(self) -> ResponseGetstatusGet200: + """получение информации о своем статусе + + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. + """ + client = await self.get_client() + async with client: + url = "/profile/status" + response = await client.get(url) + if response.is_success: + return ResponseGetstatusGet200.model_validate_json(response.text) + return None + + +async def put_status(self, data: Putstatus) -> ResponsePutstatusPut201: + """новый статус + + Метод для установки себе нового статуса. + """ + client = await self.get_client() + async with client: + url = "/profile/status" + response = await client.put(url, json=data.model_dump()) + if response.is_success: + return ResponsePutstatusPut201.model_validate_json(response.text) + if response.is_client_error: + return ResponsePutstatusPut400.model_validate_json(response.text) + return None + + +async def del_status(self): + """удаление своего статуса + + Метод для удаления своего статуса. Параметры запроса отсутствуют. + """ + client = await self.get_client() + async with client: + url = "/profile/status" + response = await client.delete(url) + return + + +async def get_tag(self, id: int) -> ResponseGettagGet200: + """получение информации о теге + + Метод для получения информации о теге. Названия тегов являются уникальными в + компании. Для получения тега вам необходимо знать его id и указать его в URL + запроса. Параметры запроса отсутствуют + """ + client = await self.get_client() + async with client: + url = self.format_url("/group_tags/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGettagGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGettagGet400.model_validate_json(response.text) + return None + + +async def get_tags( + self, per: int = None, page: int = None, +) -> ResponseGettagsGet200: + """получение актуального списка тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. Названия тегов + являются уникальными в компании. Тело запроса отсутствует, параметры передаются + в URL (например, /group_tags?per=10&page=2) + """ + client = await self.get_client() + async with client: + url = "/group_tags" + query_params = self.filter_query_params(per=per, page=page) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGettagsGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGettagsGet400.model_validate_json(response.text) + return None + + +async def get_tags_employees( + self, id: int, per: int = None, page: int = None, +) -> ResponseGettagsemployeesGet200: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. Идентификатор тега, + список сотрудников которого необходимо получить, и другие параметры передаются + в URL (например, /group_tags/877650/users?per=3&page=2) + """ + client = await self.get_client() + async with client: + url = self.format_url("/group_tags/{id}/users", {"id": id}) + query_params = self.filter_query_params(per=per, page=page) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGettagsemployeesGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGettagsemployeesGet400.model_validate_json( + response.text, + ) + return None + + +async def get_chats( + self, + sort_field: str = "id", + sort: str = "desc", + per: int = None, + page: int = None, + availability: str = None, + last_message_at_after: str = None, + last_message_at_before: str = None, +) -> ResponseGetchatsGet200: + """получение списка бесед и каналов + + Метод для получения списка бесед и каналов по заданным параметрам. Тело + запроса отсутствует, параметры передаются в URL (например, + /chats?per=2&sort[id]=desc) + """ + client = await self.get_client() + async with client: + url = "/chats" + query_params = self.filter_query_params( + sort_field=sort_field, + sort=sort, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetchatsGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGetchatsGet422.model_validate_json(response.text) + return None + + +async def create_chat(self, data: Createchat) -> ResponseCreatechatPost201: + """создание новой беседы или канала + + Метод для создания новой беседы или нового канала. При создании беседы или + канала вы автоматически становитесь участником. + """ + client = await self.get_client() + async with client: + url = "/chats" + response = await client.post(url, json=data.model_dump()) + if response.is_success: + return ResponseCreatechatPost201.model_validate_json(response.text) + if response.is_client_error: + return ResponseCreatechatPost422.model_validate_json(response.text) + return None + + +async def get_chat(self, id: int) -> ResponseGetchatGet200: + """получение информации о беседе или канале + + Получения информации о беседе или канале. Для получения беседы или канала вам + необходимо знать её id и указать его в URL запроса. + """ + client = await self.get_client() + async with client: + url = self.format_url("/chats/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGetchatGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGetchatGet400.model_validate_json(response.text) + return None + + +async def post_members_to_chats(self, data: Postmemberstochats, id: int): + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + """ + client = await self.get_client() + async with client: + url = self.format_url("/chats/{id}/members", {"id": id}) + response = await client.post(url, json=data.model_dump()) + if response.is_client_error: + return ResponsePostmemberstochatsPost422.model_validate_json( + response.text, + ) + return None + + +async def post_tags_to_chats(self, data: Posttagstochats, id: int): + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + """ + client = await self.get_client() + async with client: + url = self.format_url("/chats/{id}/group_tags", {"id": id}) + response = await client.post(url, json=data.model_dump()) + if response.is_client_error: + return ResponsePosttagstochatsPost422.model_validate_json( + response.text, + ) + return None + + +async def leave_chat(self, id: int): + """выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. Параметры запроса + отсутствуют/ + """ + client = await self.get_client() + async with client: + url = self.format_url("/chats/{id}/leave", {"id": id}) + response = await client.delete(url) + if response.is_client_error: + return ResponseLeavechatDelete400.model_validate_json( + response.text, + ) + return None + + +async def create_thread(self, id: int) -> ResponseCreatethreadPost200: + """создание нового треда + + Метод для создания нового треда к сообщению. Если у сообщения уже был создан + тред, то в ответе вернётся информация об уже созданном ранее треде. + """ + client = await self.get_client() + async with client: + url = self.format_url("/messages/{id}/thread", {"id": id}) + response = await client.post(url) + if response.is_success: + return ResponseCreatethreadPost200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseCreatethreadPost400.model_validate_json( + response.text, + ) + return None + + +async def get_list_message( + self, chat_id: int = None, per: int = None, page: int = None, +) -> ResponseGetlistmessageGet200: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в + порядке убывания даты отправки (то есть, сначала будут идти последние сообщения + чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, + /messages?chat_id=198&per=3) + """ + client = await self.get_client() + async with client: + url = "/messages" + query_params = self.filter_query_params( + chat_id=chat_id, per=per, page=page, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetlistmessageGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetlistmessageGet400.model_validate_json( + response.text, + ) + return None + + +async def create_message( + self, data: Createmessage, +) -> ResponseCreatemessagePost201: + """создание нового сообщения + + Метод для отправки сообщения в беседу или канал, личного сообщения пользователю + или комментария в тред. При использовании entity_type: "discussion" (или + просто без указания entity_type) допускается отправка любого chat_id в поле + entity_id. То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его + идентификатору или личное сообщение по идентификатору пользователя. Для + отправки личного сообщения пользователю создавать чат не требуется. Достаточно + указать entity_type: "user" и идентификатор пользователя. Чат будет создан + автоматически, если между вами ещё не было переписки. Между двумя + пользователями может быть только один личный чат. + """ + client = await self.get_client() + async with client: + url = "/messages" + response = await client.post(url, json=data.model_dump()) + if response.is_success: + return ResponseCreatemessagePost201.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseCreatemessagePost400.model_validate_json( + response.text, + ) + return None + + +async def get_message(self, id: int) -> ResponseGetmessageGet200: + """получение информации о сообщении + + Метод для получения информации о сообщении. Для получения сообщения вам + необходимо знать его id и указать его в URL запроса. + """ + client = await self.get_client() + async with client: + url = self.format_url("/messages/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGetmessageGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGetmessageGet400.model_validate_json(response.text) + return None + + +async def edit_message( + self, data: Editmessage, id: int, +) -> ResponseEditmessagePut200: + """редактирование сообщения по указанному идентификатору + + Метод для редактирования сообщения или комментария. + """ + client = await self.get_client() + async with client: + url = self.format_url("/messages/{id}", {"id": id}) + response = await client.put(url, json=data.model_dump()) + if response.is_success: + return ResponseEditmessagePut200.model_validate_json(response.text) + if response.is_client_error: + return ResponseEditmessagePut400.model_validate_json(response.text) + return None + + +async def get_message_reactions( + self, id: int, per: int = None, page: int = None, +) -> ResponseGetmessagereactionsGet200: + """получение актуального списка реакций + + Метод для получения актуального списка реакций на сообщение. Идентификатор + сообщения, список реакций на которое необходимо получить, передается в URL + (например, /messages/7231942/reactions). Количество возвращаемых сущностей и + страница выборки указываются в теле запроса + """ + client = await self.get_client() + async with client: + url = self.format_url("/messages/{id}/reactions", {"id": id}) + query_params = self.filter_query_params(per=per, page=page) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetmessagereactionsGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetmessagereactionsGet400.model_validate_json( + response.text, + ) + return None + + +async def post_message_reactions(self, data: Postmessagereactions, id: int): + """добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый + пользователь может установить не более 20 уникальных реакций на сообщение. - + Сообщение может иметь не более 30 уникальных реакций. - Сообщение может иметь + не более 1000 реакций. + """ + client = await self.get_client() + async with client: + url = self.format_url("/messages/{id}/reactions", {"id": id}) + response = await client.post(url, json=data.model_dump()) + if response.is_client_error: + return ResponsePostmessagereactionsPost400.model_validate_json( + response.text, + ) + return None + + +async def delete_message_reactions(self, id: int, code: str = None): + """удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, + которые были поставлены авторизованным пользователем. + """ + client = await self.get_client() + async with client: + url = self.format_url("/messages/{id}/reactions", {"id": id}) + query_params = self.filter_query_params(code=code) + response = await client.delete(url, params=query_params) + if response.is_client_error: + return ResponseDeletemessagereactionsDelete400.model_validate_json( + response.text, + ) + return None + + +async def create_task(self, data: Createtask) -> ResponseCreatetaskPost201: + """создание нового напоминания + + Метод для создания нового напоминания. При создании напоминания обязательным + условием является указания типа напоминания: звонок, встреча, простое + напоминание, событие или письмо. При этом не требуется дополнительное описание + - вы просто создадите напоминание с соответствующим текстом. Если вы укажите + описание напоминания - то именно оно и станет текстом напоминания. У + напоминания должны быть ответственные, если их не указывать - ответственным + назначаетесь вы. + """ + client = await self.get_client() + async with client: + url = "/tasks" + response = await client.post(url, json=data.model_dump()) + if response.is_success: + return ResponseCreatetaskPost201.model_validate_json(response.text) + if response.is_client_error: + return ResponseCreatetaskPost400.model_validate_json(response.text) + return None From 8ccf9c02776d2d20ecf2235c1a8e6670442d9ce4 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 13 Jan 2025 21:57:12 +0300 Subject: [PATCH 263/296] fixed change --- src/generator1/pachca.py | 22 +++++++++++++--------- src/generator1/script.py | 1 - 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 4f527a8..baac452 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -5,7 +5,19 @@ from dotenv import load_dotenv from logger_setup import setup_logging from pachca_api_open_api_3_0_client.client import Pachca +from pachca_api_open_api_3_0_client.models import ( + CreateTaskBodyTask, + EditMessageBody, + EditMessages, + GroupTag, + MembersChat, + QueryStatusStatus, +) +from pachca_api_open_api_3_0_client.models.base_chat import BaseChat from pachca_api_open_api_3_0_client.models.chat import Chat +from pachca_api_open_api_3_0_client.models.code_reaction import ( + CodeReaction, +) from pachca_api_open_api_3_0_client.models.create_chat_body import ( CreateChatBody, ) @@ -18,14 +30,6 @@ from pachca_api_open_api_3_0_client.models.create_task_body import ( CreateTaskBody, ) -from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, QueryStatusStatus, EditMessages, EditMessageBody, - GroupTag, MembersChat -) -from pachca_api_open_api_3_0_client.models.base_chat import BaseChat -from pachca_api_open_api_3_0_client.models.code_reaction import ( - CodeReaction, -) from pachca_api_open_api_3_0_client.models.put_status_body import ( PutStatusBody, ) @@ -223,7 +227,7 @@ async def main() -> None: result = task logger.debug( f"{task}: data={result} \n" - "**", + "***", ) logger.debug('Tests ended '+'*'*100) diff --git a/src/generator1/script.py b/src/generator1/script.py index 49f66d8..f6c14a6 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -151,7 +151,6 @@ def get_base_url_from_yaml(openapi_yaml): "79", ], check=True, - shell=True, ) subprocess.run( [ From e93e48c5c03d3b6118333451d776d686318a24f2 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 22:21:10 +0300 Subject: [PATCH 264/296] add about logging --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 3bf5122..2fa4c35 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ _src/generator2/_ - Основной запуск генерации необходимых файлов для клиента - Форматтинг и правка сгенерированного кода в автоматическом режиме + --- ## 🚀 Установка и использование @@ -280,6 +281,12 @@ _src/generator2/_ python -m generator2_full.pachca ``` +5. **Логирование** + В проекте предусмотрено логирование результатов работы генератора и тестовых запросов, логи сохраняются в директроии generator2 + pachca_log.log - лог работы тестовых запросов. + client_generator.log - лог работы генератора клиента. + + ## 💡 Команда генератора - [Алексей Малков](https://github.com/shft1) - [Дмитрий Костин](https://github.com/k0sdm1) From e690a6281e40a5e947f5c86371aba58dd1bc8211 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 22:22:24 +0300 Subject: [PATCH 265/296] add about logging --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2fa4c35..84f3593 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,6 @@ _src/generator2/_ - Основной запуск генерации необходимых файлов для клиента - Форматтинг и правка сгенерированного кода в автоматическом режиме - --- ## 🚀 Установка и использование From 972e5796e531551b6a0d093d2e6e379112666556 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 22:26:38 +0300 Subject: [PATCH 266/296] add about logging --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 84f3593..8c7e505 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,10 @@ _src/generator2/_ 5. **Логирование** В проекте предусмотрено логирование результатов работы генератора и тестовых запросов, логи сохраняются в директроии generator2 pachca_log.log - лог работы тестовых запросов. + - Содержит результаты выполнения тестовых запросов, информация о том, что выдал сервер. client_generator.log - лог работы генератора клиента. + - Содержит сведения о том, какие пути были обработаны + - Содержит сведения о том, что форматтинг кода завершен ## 💡 Команда генератора From cda375b80c2378610c791a96450ed601c6b63886 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 22:28:18 +0300 Subject: [PATCH 267/296] formatting --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c7e505..e593706 100644 --- a/README.md +++ b/README.md @@ -280,7 +280,8 @@ _src/generator2/_ python -m generator2_full.pachca ``` -5. **Логирование** +5. **Логирование**: + В проекте предусмотрено логирование результатов работы генератора и тестовых запросов, логи сохраняются в директроии generator2 pachca_log.log - лог работы тестовых запросов. - Содержит результаты выполнения тестовых запросов, информация о том, что выдал сервер. From 39fcdd43bfdbaba36566c9cfded6887d99e80b95 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 22:28:52 +0300 Subject: [PATCH 268/296] formatting --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e593706..0baf5cc 100644 --- a/README.md +++ b/README.md @@ -283,8 +283,10 @@ _src/generator2/_ 5. **Логирование**: В проекте предусмотрено логирование результатов работы генератора и тестовых запросов, логи сохраняются в директроии generator2 + pachca_log.log - лог работы тестовых запросов. - Содержит результаты выполнения тестовых запросов, информация о том, что выдал сервер. + client_generator.log - лог работы генератора клиента. - Содержит сведения о том, какие пути были обработаны - Содержит сведения о том, что форматтинг кода завершен From 1795ce94f5bcb7e3233d8d866c1a6dbbf4987fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 13 Jan 2025 22:31:04 +0300 Subject: [PATCH 269/296] README --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3bf5122..3274d0d 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,14 @@ _src/generator1/_ #### 📁 pachca-api-open-api-3-0-client/ - директория автоматически сгенерированного кода +#### 🛠️ client_generator.log +- Автоматически генерируемый файл (появляется после запуска тестового скрипта) +- Логгирует асинхронные методы, отражает работу методов + +#### 🛠️ pachca_testresults.log +- Автоматически генерируемый файл (появляется после запуска тестового скрипта) +- Логгирует тестовые функции, отражает полученные данные в тестах + --- ## 🚀 Установка и использование @@ -117,21 +125,13 @@ _src/generator1/_ .\venv\scripts\activate pip install -r requirements.txt ``` -3. **Запустите генерацию клиента**: - ```bash - openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite - ``` -4. **Запустите скрипт-генератор**: +3. **Запустите генерацию клиента:**: ```bash - python script.py + python generator.py generate ``` -5. **Установить pachca-api-open-api-3-0-client в venv командой**: - ```bash - pip install ./pachca-api-open-api-3-0-client - ``` -6. **Запустите пример запроса**: +4. **Запустите пример запроса**: ```bash - python pachca.py + python generator.py test ``` ## 💡 Команда генератора @@ -367,4 +367,4 @@ _src/builder/_ **📄 Документация API**: [Pachca API Documentation](https://crm.pachca.com/dev/getting-started/requests-and-responses/) ---- +--- \ No newline at end of file From 36e41bfa194e4afa8c21bfb1a8066c541fa14181 Mon Sep 17 00:00:00 2001 From: k0sdm1 Date: Mon, 13 Jan 2025 22:31:09 +0300 Subject: [PATCH 270/296] constants add --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0baf5cc..839fade 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ _src/generator2/generator2_full_ #### 🔧 constants.py - Константы клиента - Константы логгера +- Базовый адрес API, автоматически подтягивается из документации #### 🧪 pachca.py - Пример использования сгенерированного API клиента From 9a053358a219ce46f24ab303a40cb0c77dfd8d52 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 13 Jan 2025 22:33:36 +0300 Subject: [PATCH 271/296] delete generate code --- src/generator2/generator2_full/constants.py | 0 .../generator2_full/request_methods.py | 608 ------------------ src/main.py | 6 - src/repository/README.md | 2 +- .../pachca_generator1-1.0.0-py3-none-any.whl | Bin 128944 -> 0 bytes .../pachca_generator2-1.0.0-py3-none-any.whl | Bin 137640 -> 0 bytes 6 files changed, 1 insertion(+), 615 deletions(-) delete mode 100644 src/generator2/generator2_full/constants.py delete mode 100644 src/generator2/generator2_full/request_methods.py delete mode 100644 src/main.py delete mode 100644 src/repository/pachca_generator1-1.0.0-py3-none-any.whl delete mode 100644 src/repository/pachca_generator2-1.0.0-py3-none-any.whl diff --git a/src/generator2/generator2_full/constants.py b/src/generator2/generator2_full/constants.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py deleted file mode 100644 index 04e6a41..0000000 --- a/src/generator2/generator2_full/request_methods.py +++ /dev/null @@ -1,608 +0,0 @@ -from .models.models_reqBod_createChat import Createchat -from .models.models_reqBod_createMessage import Createmessage -from .models.models_reqBod_createTask import Createtask -from .models.models_reqBod_editMessage import Editmessage -from .models.models_reqBod_getDirectUrl import Getdirecturl -from .models.models_reqBod_postMembersToChats import Postmemberstochats -from .models.models_reqBod_postMessageReactions import Postmessagereactions -from .models.models_reqBod_postTagsToChats import Posttagstochats -from .models.models_reqBod_putStatus import Putstatus -from .models.models_response_createChatpost201 import ResponseCreatechatPost201 -from .models.models_response_createChatpost422 import ResponseCreatechatPost422 -from .models.models_response_createMessagepost201 import ( - ResponseCreatemessagePost201, -) -from .models.models_response_createMessagepost400 import ( - ResponseCreatemessagePost400, -) -from .models.models_response_createTaskpost201 import ResponseCreatetaskPost201 -from .models.models_response_createTaskpost400 import ResponseCreatetaskPost400 -from .models.models_response_createThreadpost200 import ( - ResponseCreatethreadPost200, -) -from .models.models_response_createThreadpost400 import ( - ResponseCreatethreadPost400, -) -from .models.models_response_deleteMessageReactionsdelete400 import ( - ResponseDeletemessagereactionsDelete400, -) -from .models.models_response_editMessageput200 import ResponseEditmessagePut200 -from .models.models_response_editMessageput400 import ResponseEditmessagePut400 -from .models.models_response_getChatget200 import ResponseGetchatGet200 -from .models.models_response_getChatget400 import ResponseGetchatGet400 -from .models.models_response_getChatsget200 import ResponseGetchatsGet200 -from .models.models_response_getChatsget422 import ResponseGetchatsGet422 -from .models.models_response_getCommonMethodsget200 import ( - ResponseGetcommonmethodsGet200, -) -from .models.models_response_getCommonMethodsget400 import ( - ResponseGetcommonmethodsGet400, -) -from .models.models_response_getEmployeeget200 import ResponseGetemployeeGet200 -from .models.models_response_getEmployeeget400 import ResponseGetemployeeGet400 -from .models.models_response_getEmployeesget200 import ( - ResponseGetemployeesGet200, -) -from .models.models_response_getListMessageget200 import ( - ResponseGetlistmessageGet200, -) -from .models.models_response_getListMessageget400 import ( - ResponseGetlistmessageGet400, -) -from .models.models_response_getMessageReactionsget200 import ( - ResponseGetmessagereactionsGet200, -) -from .models.models_response_getMessageReactionsget400 import ( - ResponseGetmessagereactionsGet400, -) -from .models.models_response_getMessageget200 import ResponseGetmessageGet200 -from .models.models_response_getMessageget400 import ResponseGetmessageGet400 -from .models.models_response_getStatusget200 import ResponseGetstatusGet200 -from .models.models_response_getTagget200 import ResponseGettagGet200 -from .models.models_response_getTagget400 import ResponseGettagGet400 -from .models.models_response_getTagsEmployeesget200 import ( - ResponseGettagsemployeesGet200, -) -from .models.models_response_getTagsEmployeesget400 import ( - ResponseGettagsemployeesGet400, -) -from .models.models_response_getTagsget200 import ResponseGettagsGet200 -from .models.models_response_getTagsget400 import ResponseGettagsGet400 -from .models.models_response_getUploadspost200 import ResponseGetuploadsPost200 -from .models.models_response_leaveChatdelete400 import ( - ResponseLeavechatDelete400, -) -from .models.models_response_postMembersToChatspost422 import ( - ResponsePostmemberstochatsPost422, -) -from .models.models_response_postMessageReactionspost400 import ( - ResponsePostmessagereactionsPost400, -) -from .models.models_response_postTagsToChatspost422 import ( - ResponsePosttagstochatsPost422, -) -from .models.models_response_putStatusput201 import ResponsePutstatusPut201 -from .models.models_response_putStatusput400 import ResponsePutstatusPut400 - - -async def get_common_methods( - self, entity_type: str = None, -) -> ResponseGetcommonmethodsGet200: - """получение списка актульных полей сущности - - Метод для получения актуального списка дополнительных полей участников и - напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в - URL (например, /custom_properties?entity_type=User) - """ - client = await self.get_client() - async with client: - url = "/custom_properties" - query_params = self.filter_query_params(entity_type=entity_type) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetcommonmethodsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetcommonmethodsGet400.model_validate_json( - response.text, - ) - return None - - -async def get_uploads(self) -> ResponseGetuploadsPost200: - """получения подписи и ключа для загрузки файла - - Данный метод необходимо использовать для загрузки каждого файла. Данный метод - позволяет получить уникальный набор параметров для загрузки файла. Параметры - запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/uploads" - response = await client.post(url) - if response.is_success: - return ResponseGetuploadsPost200.model_validate_json(response.text) - return None - - -async def get_direct_url(self, data: Getdirecturl): - """(полученный в ответе на запрос /uploads) загрузка файла - - Данный метод не требует авторизации. Получив все параметры, вам необходимо - сделать POST запрос в формате multipart/form-data на адрес, который был указан - в поле direct_url, отправив полученные параметры и сам файл. - """ - client = await self.get_client() - async with client: - url = "/direct_url" - response = await client.post(url, json=data.model_dump()) - return - - -async def get_employees( - self, per: int = None, page: int = None, query: str = None, -) -> ResponseGetemployeesGet200: - """получение актуального списка всех сотрудников компании - - Метод для получения актуального списка сотрудников вашей компании. Тело запроса - отсутствует, параметры передаются в URL (например, - /users?per=50&page=2&query=example.com) - """ - client = await self.get_client() - async with client: - url = "/users" - query_params = self.filter_query_params( - per=per, page=page, query=query, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetemployeesGet200.model_validate_json( - response.text, - ) - return None - - -async def get_employee(self, id: int) -> ResponseGetemployeeGet200: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. Для получения сотрудника вам - необходимо знать его id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = self.format_url("/users/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetemployeeGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetemployeeGet400.model_validate_json(response.text) - return None - - -async def get_status(self) -> ResponseGetstatusGet200: - """получение информации о своем статусе - - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.get(url) - if response.is_success: - return ResponseGetstatusGet200.model_validate_json(response.text) - return None - - -async def put_status(self, data: Putstatus) -> ResponsePutstatusPut201: - """новый статус - - Метод для установки себе нового статуса. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.put(url, json=data.model_dump()) - if response.is_success: - return ResponsePutstatusPut201.model_validate_json(response.text) - if response.is_client_error: - return ResponsePutstatusPut400.model_validate_json(response.text) - return None - - -async def del_status(self): - """удаление своего статуса - - Метод для удаления своего статуса. Параметры запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.delete(url) - return - - -async def get_tag(self, id: int) -> ResponseGettagGet200: - """получение информации о теге - - Метод для получения информации о теге. Названия тегов являются уникальными в - компании. Для получения тега вам необходимо знать его id и указать его в URL - запроса. Параметры запроса отсутствуют - """ - client = await self.get_client() - async with client: - url = self.format_url("/group_tags/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGettagGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGettagGet400.model_validate_json(response.text) - return None - - -async def get_tags( - self, per: int = None, page: int = None, -) -> ResponseGettagsGet200: - """получение актуального списка тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. Названия тегов - являются уникальными в компании. Тело запроса отсутствует, параметры передаются - в URL (например, /group_tags?per=10&page=2) - """ - client = await self.get_client() - async with client: - url = "/group_tags" - query_params = self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGettagsGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGettagsGet400.model_validate_json(response.text) - return None - - -async def get_tags_employees( - self, id: int, per: int = None, page: int = None, -) -> ResponseGettagsemployeesGet200: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. Идентификатор тега, - список сотрудников которого необходимо получить, и другие параметры передаются - в URL (например, /group_tags/877650/users?per=3&page=2) - """ - client = await self.get_client() - async with client: - url = self.format_url("/group_tags/{id}/users", {"id": id}) - query_params = self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGettagsemployeesGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGettagsemployeesGet400.model_validate_json( - response.text, - ) - return None - - -async def get_chats( - self, - sort_field: str = "id", - sort: str = "desc", - per: int = None, - page: int = None, - availability: str = None, - last_message_at_after: str = None, - last_message_at_before: str = None, -) -> ResponseGetchatsGet200: - """получение списка бесед и каналов - - Метод для получения списка бесед и каналов по заданным параметрам. Тело - запроса отсутствует, параметры передаются в URL (например, - /chats?per=2&sort[id]=desc) - """ - client = await self.get_client() - async with client: - url = "/chats" - query_params = self.filter_query_params( - sort_field=sort_field, - sort=sort, - per=per, - page=page, - availability=availability, - last_message_at_after=last_message_at_after, - last_message_at_before=last_message_at_before, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetchatsGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetchatsGet422.model_validate_json(response.text) - return None - - -async def create_chat(self, data: Createchat) -> ResponseCreatechatPost201: - """создание новой беседы или канала - - Метод для создания новой беседы или нового канала. При создании беседы или - канала вы автоматически становитесь участником. - """ - client = await self.get_client() - async with client: - url = "/chats" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatechatPost201.model_validate_json(response.text) - if response.is_client_error: - return ResponseCreatechatPost422.model_validate_json(response.text) - return None - - -async def get_chat(self, id: int) -> ResponseGetchatGet200: - """получение информации о беседе или канале - - Получения информации о беседе или канале. Для получения беседы или канала вам - необходимо знать её id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetchatGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetchatGet400.model_validate_json(response.text) - return None - - -async def post_members_to_chats(self, data: Postmemberstochats, id: int): - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}/members", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePostmemberstochatsPost422.model_validate_json( - response.text, - ) - return None - - -async def post_tags_to_chats(self, data: Posttagstochats, id: int): - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}/group_tags", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePosttagstochatsPost422.model_validate_json( - response.text, - ) - return None - - -async def leave_chat(self, id: int): - """выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. Параметры запроса - отсутствуют/ - """ - client = await self.get_client() - async with client: - url = self.format_url("/chats/{id}/leave", {"id": id}) - response = await client.delete(url) - if response.is_client_error: - return ResponseLeavechatDelete400.model_validate_json( - response.text, - ) - return None - - -async def create_thread(self, id: int) -> ResponseCreatethreadPost200: - """создание нового треда - - Метод для создания нового треда к сообщению. Если у сообщения уже был создан - тред, то в ответе вернётся информация об уже созданном ранее треде. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/thread", {"id": id}) - response = await client.post(url) - if response.is_success: - return ResponseCreatethreadPost200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatethreadPost400.model_validate_json( - response.text, - ) - return None - - -async def get_list_message( - self, chat_id: int = None, per: int = None, page: int = None, -) -> ResponseGetlistmessageGet200: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в - порядке убывания даты отправки (то есть, сначала будут идти последние сообщения - чата). Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, - /messages?chat_id=198&per=3) - """ - client = await self.get_client() - async with client: - url = "/messages" - query_params = self.filter_query_params( - chat_id=chat_id, per=per, page=page, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetlistmessageGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetlistmessageGet400.model_validate_json( - response.text, - ) - return None - - -async def create_message( - self, data: Createmessage, -) -> ResponseCreatemessagePost201: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, личного сообщения пользователю - или комментария в тред. При использовании entity_type: "discussion" (или - просто без указания entity_type) допускается отправка любого chat_id в поле - entity_id. То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его - идентификатору или личное сообщение по идентификатору пользователя. Для - отправки личного сообщения пользователю создавать чат не требуется. Достаточно - указать entity_type: "user" и идентификатор пользователя. Чат будет создан - автоматически, если между вами ещё не было переписки. Между двумя - пользователями может быть только один личный чат. - """ - client = await self.get_client() - async with client: - url = "/messages" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatemessagePost201.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatemessagePost400.model_validate_json( - response.text, - ) - return None - - -async def get_message(self, id: int) -> ResponseGetmessageGet200: - """получение информации о сообщении - - Метод для получения информации о сообщении. Для получения сообщения вам - необходимо знать его id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetmessageGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetmessageGet400.model_validate_json(response.text) - return None - - -async def edit_message( - self, data: Editmessage, id: int, -) -> ResponseEditmessagePut200: - """редактирование сообщения по указанному идентификатору - - Метод для редактирования сообщения или комментария. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}", {"id": id}) - response = await client.put(url, json=data.model_dump()) - if response.is_success: - return ResponseEditmessagePut200.model_validate_json(response.text) - if response.is_client_error: - return ResponseEditmessagePut400.model_validate_json(response.text) - return None - - -async def get_message_reactions( - self, id: int, per: int = None, page: int = None, -) -> ResponseGetmessagereactionsGet200: - """получение актуального списка реакций - - Метод для получения актуального списка реакций на сообщение. Идентификатор - сообщения, список реакций на которое необходимо получить, передается в URL - (например, /messages/7231942/reactions). Количество возвращаемых сущностей и - страница выборки указываются в теле запроса - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/reactions", {"id": id}) - query_params = self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetmessagereactionsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetmessagereactionsGet400.model_validate_json( - response.text, - ) - return None - - -async def post_message_reactions(self, data: Postmessagereactions, id: int): - """добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый - пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - Сообщение может иметь - не более 1000 реакций. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/reactions", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePostmessagereactionsPost400.model_validate_json( - response.text, - ) - return None - - -async def delete_message_reactions(self, id: int, code: str = None): - """удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, - которые были поставлены авторизованным пользователем. - """ - client = await self.get_client() - async with client: - url = self.format_url("/messages/{id}/reactions", {"id": id}) - query_params = self.filter_query_params(code=code) - response = await client.delete(url, params=query_params) - if response.is_client_error: - return ResponseDeletemessagereactionsDelete400.model_validate_json( - response.text, - ) - return None - - -async def create_task(self, data: Createtask) -> ResponseCreatetaskPost201: - """создание нового напоминания - - Метод для создания нового напоминания. При создании напоминания обязательным - условием является указания типа напоминания: звонок, встреча, простое - напоминание, событие или письмо. При этом не требуется дополнительное описание - - вы просто создадите напоминание с соответствующим текстом. Если вы укажите - описание напоминания - то именно оно и станет текстом напоминания. У - напоминания должны быть ответственные, если их не указывать - ответственным - назначаетесь вы. - """ - client = await self.get_client() - async with client: - url = "/tasks" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatetaskPost201.model_validate_json(response.text) - if response.is_client_error: - return ResponseCreatetaskPost400.model_validate_json(response.text) - return None diff --git a/src/main.py b/src/main.py deleted file mode 100644 index 7d16819..0000000 --- a/src/main.py +++ /dev/null @@ -1,6 +0,0 @@ -# Это основной запускаемый файл. -# Заменить содержимое своим кодом. - -import sys - -print(sys.path) diff --git a/src/repository/README.md b/src/repository/README.md index 5e32573..2a95115 100644 --- a/src/repository/README.md +++ b/src/repository/README.md @@ -1 +1 @@ -Результат - Библиотека \ No newline at end of file +Тут хранятся сгенерированные пакеты генераторов \ No newline at end of file diff --git a/src/repository/pachca_generator1-1.0.0-py3-none-any.whl b/src/repository/pachca_generator1-1.0.0-py3-none-any.whl deleted file mode 100644 index 89d3af778d40fbf8b6dbfe60b282f2fbb1582155..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128944 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 G22F?Nk9x` zv}uM=b3ltStqQYP#-Xmv8N7=eB=5#_75dOQ4lA9qg15c0HKd8-8^Vwq!(n!z_N zcam~sgC-Io+(KJ@4`a5#E(I>#FoP}z>3qcbq~!E9l2%s~&*@w7_+6uttq)pHty1n2 zz*I9++I#h*!Q^mc`yqZ9SK1U+o5?yMj40|BN&x-f(ofP3;eiEVj-Jqkbx#GdwQHRo z`bqv!3+6ZMyRbeFMD!QqLk!&xK>-+EJ%%8z4rtEb;9NFz6`H5{9r>v9_ZPNmM~3)2t71 z3Gd!SF|3ME9Y@4=))NJ0q{?R2Ttzui&|27KJSPrBl*n#Rh7u39Fkv>ZHTg^%MPE`3JC*!x{V3*W;nmV;_eLNcjr(SBJ;zZCNr0MAK_7vq4 zTF7fKiP;p6`ItkqUX^X#Y{xF$b?ubPv$9+Hh_U*;3Rgvm zL7WE-LEGgbKD6b15@@1x(kw+bXO$+I+|n-Np{jn#+w}wY$GN^!FJ7Iht6sOnQkPoL zGtqO>mt%-=h1qrE4G!l1b7ME}_;7zR@(A#IR=m%^*&Ctf))+`1S$)h;fs3JK$UeD( z#yNQFqT+bSR7Z+!fbZls%V~D&f%$Mw$)2PA|dex0aFcYo{c zz8^|8Z~shpQK$%>A!uo_~oX{-1Pu6@X3`#M0!#B!pT>(PRXaH4{Ve zr?={21Z|7#$}?%W*G1c7mS@t?5pQdE;t9fD_uNqL!Q&&f%k%!p&FbRmG`Ln-x1Y>r zxb7ONU15=m#OxE(MOOWAg$9cP^cFg1cH_1l@bb4`zmem7AjcX8)CZut+CJQyu4St2 zB#1Hrd^*?_w6mvnn;?~v(UQiAz46W zOF33Ob6_Ymt!Z$`GejknP_gf~_KAG3^U|A`tOfZy6M4=gYVB zRan>BQ+sZ{%Ro@&$km5O+B9 zw7`!yEg_*3L(oE&I*deyX%q{j$hv$P&Nk5rc{8f^Q7Z<&bh}h69g`|C%SO{G%M5EC zAGAe>)=q1=RNoBZAi|_a!!JZ9`~@v@-qyv%Kq9KFEZ4SELER)dJTLTmXR;i}138Qp z)IfyP0uCoZz@EQ%S>DktT^U<=d$oV+Zr}}!-74l?!iO=!0>ZvP{zu@UP>5L@Kczj2?rn9bAZjvH)X=f#}@>+9t$dhHazUxq9v2p#_o#G-#y#ygUyyAxq7Pn zanBf6yqJ7D{^CfQ0#5}T#RLolC14CK_wb`w{EsrY*(GKuOcdBG$g3x5308hi8oY6` z-uOdBt-x#P2C;;rOeH^=MrjG6or7*WHYj*grAIwXWLSwfyyMulrlE4dDXFt~2euaqP;eM!v^D<$vI4lS6N z#{V?{eQw?z%JMK@R3A4qZwcK7_MFQ23N)R6U+;Ld7N_zFns@XOxkV&os9 zp0cS8+_{cq^25J>t#Qq8b59i^xqF?S#qKg!Txn8>bpV#{6v*k{fjKf=)o1%aG?TNn zto7km=~n)X^@#y%nQt5p(~oUidm>}mG}Ao`npw(7Claz%00O)|*lqen{g2sGV@v+e~3t zld^kae=buR-DgoO(nS=bz@xtkNPp=xg#ILh45Bf76rjdiZOBART#%IdLK&JzGQ4&R zLIT|TQTGb-fKyztzO?T0sOJa)edXkPudKW%x9ApMD%GcoC4~U3X<|M#s?v}VzpgCS z1ABwzo>RwSp9Q`HGIhIyj{XZ=iUJyDC(^k`hk*biYA7BAHJ5bX3t`M0)ceEguu@w| zFn(dw-Y*Px@$&**Ss^fp273VEG=P5edd z3zl|QFn)_gFW~4KevXIH5h(m>A4j2_(Ld?Y)v`F3f#yR3u>TKd-@u&to~9k!NyoNr zn;omej%}MA+jcs(ZL4FuW83MxPoJ|hJLl}aRWqBae1NCwcl~c&s3ZzSoXfl}*k2Cy z^Tb5voUr7qejIbR_U^u28Je?g%CWR7a ze<6hQ!+Y=a>t2e5F*S7hB{)n9?&YQauKUg{-XAc?uKtUbfe^$S^tULpDx&`e#ZGu6u0R6XhHjSEQqTRW3a1! z040h&)Nfu_cd7`bNSvC5YO!%G*GC7ny@h7B21v*dQS8Btcs zDknwjx#`@=x`Iy~fEb#Bl+yJcQ)ftGG6TKPgK>3;^*2rt5{mn@^c#aV@ss^>mlV24 zePeJbB`%T%=-j#UR(XrjsB^Vhu?*RjT*?72%p#!J0Hir_qS!E&$N~sh>@))yWropU zdzZ^Ey_+%<+1c!D!zJd0Xmr->kBOmP`28^;FpVR>@GUbw3`=mRg1YIj#Guh90WNwl z%oTJ&f+|al5Z_>6I$<1P#K~ZkPGery{gy2|$lr=y+PdnfK77OeMEJ~EC);qK!{ zs3*yc#mttZonI}Oy}xrr?yRwP5pS$*gw#!l7)Br!$m1_eOD2_8lOixnwJVgYhO+8A5zQNIO0z~ya%~|eyICO5-ONc> z$q4tJc^Qhg`&`2>y2*w@qEvzyKJaQKkiyVVi#inK6M>U|ns(qQ3nhHClUPBwhA0=y3NzDVw~jvrn&l8xN>ODq=QqP;a@!c* zd$Q;vp@80!sKK^SdF5{`_PS4J5=3dS@0npVl*PuNb`W4%)**2FE;4p~@aRp%QT`Qh zmz@TaEhz4n>xQfY1lj2CWXE9$d41-H`+C%Cp0DZ@0>P<7RAmuvX7wm+3VDP{P(!Vk zNHsAJX^#CUC%I01iZJ#}@YkM{bJY|4_cd)EFm7@G+hy(#((XUVOaByc{Ok7M4?f;$ zoR5MBS~^W4(l>+A(h@o>8LHHuzdY6JaL2f`?2g&NumuO-DBKp1+c3^9ABUO3GE-Ov$Cz& z7wNOUt5<6SC*){m$v1YaV_SkAhX?Pno#f-)+mSF&fV6;?u7%YQ>FdXlu9 zWGOK-S6RYnBE~BcT+u_Tr3gE4PU>raG>ycd{vn=Sa7eNS*-V`ToEJ17JQm+B-b!&h zE?-QamjnK7*(-A%@p4vQwe3$fp51e;@%$4NI-jhq%J1btoxMU{mSnLPy>b5X5dQhY zNw>T-w@q{w+*N-$55{P4##VTin#tvWo|uLq*jd)9jSJRMmG)g$ZZ2po7aP(#t}Su z>^Dawhi!4pO{CqE->ZYzb?3f4ox2vf?!i@^k;-a2)2oz42{^=?cK#S?h&Au;py?-L z{c>)wRpqJmBzJV!(q!<1SMx`4o9IvVe#w(%tYwqc zaGNqP*6#Ya$@ksj9@uJ0@*e1B`e?E5VW}Cu{Z~WlubbxwLkRV`P;ag!`=g%rD0B#GwVtrV4i(wx51n4r0g)pl% z=1#;L)C}Y)jrCoJni_c3k-4)Z$Vy0qf)Im{_C;dfs*?&^qi08U?yJPM?v27n8W8w=KIdY zd)N>p;G0avnZJ=9@B)49?*XfWhX2T?`d>fOe~|D14zP2Aza3!VTFpV35EVj8PG16B zpwxt{i& z9l4i?{EbU`{#I1L?#n?UTAFc57tRPJ2z?=&xAXOl7geAGF>lO)jtwkg@A#ATSR@*6 z+d7P5-Oz{s%K@W|WdOL8q&WBh1C)FTVaCw;=gRE?Y^UIsFOZ%#TsOUsZ$p_)yJ;n7b2TKhHp zYiVb0hlSf~^~1mWGKAsk=<(O#4vmMTLkHae$fVrrWInpCX;?uk^`Z1WhbZ{I!S`R2 zPP-4@@%pq9=+~SKu^r-zD!42PzM@sn6(t6uW%C zhaIe3DjJ0upam9Tr;40BNdX4i0o+xa24V0VlU>@iUQ{Lv+}2p6H7WYNHN#!qG5rl} zFzPdey0QEKAAq^RmF>l0Rtz_7gVs_&=KXY36Vdd^j#kWqN z8VnD+gs^{QNKu+XRbk%UY>HsN(LRplSDP8Hrrrk4A|Wa*@IrpPTTRs3$~5Ehl#9~q zPNH4ww8kuLU2-SyIgsdY9rYE-r%2b_&T8V$o)Pl{Jmb@M=#R+|lnFlvt^(tf&S|aj zA?46jjoEA?u;GH`9u>%ki-+o|R7+s>sVrX-%@li$8!r}bidcwS7xh6(GosrsY~*mZ zoZ#3S8s&&(!cn=n#QQ$5IX+k|JftnNv9gXGc@>S9K0^iaNm&=%_S!#H?5=yV^bu96Qi@1 zPuJjTG#ry+<816dWu>~hJ(h$j!mPyU@0=$ePeZH{hq8}B%%~_}t3rD87Kr)tisnjZ zZP^QqNA%LZmJBwmdRJR;FvhTj1X>k=Axrw(iEiz3wM9zuK-3A^R>Bf6*rJ3du&4 z!(ZJ6LYKm8WD9Q*szj3n_s@;?M9<*4k-iBi5ds>Q%Rpx$%smnzfI*Xjy({%Q`O-+O zb)&xRT`&dr$l&T;7{IF%Y`uBI(Vdl*mX)@lT&Hd9KDt}72N31)-12JG-MA$cB5Ejg zuf1+}Zd_f+yI%e}+kDT7TvW8#X0!N1wJh{JQl zCqI^u8tu=I9BWKJlK@)z6zU1)CV1J*yuT9g3grX*QwfQ7c!BnE%eSUIgq)falOk;` zIrDPy0`MwPz5cvIr9VnsSc{IWU*Ec>Dp33H7 zl+`e~aKG1VtgKt*NBQlE#cfO5vX`2UO3DHj?^j#=+7oAIoz8XMO5L81A7)Ru{5f?S zF(j!e@+&x~g97q5`EYY)qd2!{#`Fj7ja;gB(>^pW1PdDXFb(d|n&zdfY2M3hV&$vh zK@0^(Gs4#lsn;EC>%5!1AjdRMj^vaaIiNFX#2R?URETr;H%ROuIj1z4&D@aXAPFdu zTvoXbqjPm)XFmuZu#3FE-TEVsa7kyff1_Jo#~8SA)$C!3_ZjOMUdllIvVdBcT}P=) zPK5*V;mCaZDfRgqI$fp!c0HTT>&^ife;;hDS9Hw@iZ0z!1T!>26&ER?$s1fRu>AA` zrfhS0^5DcH*gjC}#RRU^5 zizlqE2kw=hXfL*^40ohJmoO`Z%l$J~=OZxS-e-Y+g6j^LDKR^^sIIc6pyEb#N57v zrr}sdi}}9Z>aq#i#|H<%~LDI4c*))LUob&H+EU&>3UC6^}f(W&ma?E zn}VKm#0*sX+M#=P{&{ZXMSgGa)eI^+MIofw%*9Y5*TqHOFYr{btO*t2VN0paFci=y z>2Z?=>0>n>+G^Tnor!8o*cjy$>%mm8%q3@{n_|_%HZ}Tjv6JG=5O9 zAB}kgLeP*_PkqORmNbAA2f<#39zpqjHoZ@l1&1xkfyFv9*ma&RXe|ou#GVfxv&%^Z zj7~>uIXoKqCR|LO$cV_%PbxdMJ)Al3{&*HnKA4HF*$1aJ$ zYXUWdx3sSMPQi#oJYw762RSp@qdZ#PpOCD6=8WtyofKt=(!dSp<=7O;#$=V-!SSBh z%l9=ioAl!pp{64+mb?{lw67H@Kj%lxNCs-TXT;+>3YYD3#bhTxmYaYc(DH$QPk3%h;n7b#f8uUo&XQ?`7{7iC^nN{knJ-sU;_*^k*jm|~c zx2GhZ_iIlX(WXvUUrW*QlE8*ri0-)j;WZH&$jH@X;{kj%Z0bcwn^+#!DP>a_UJ}Uv4dTgpXAbRGem3 zXs`7h@q20`&^2~eM6c#ofyZ4DN~WE_(Y&=-A5j>2t2R?6N}R{jcjDE=(!e#`T4JR} zP(Bi+-P2H&&Oo7KwF{s5Xk6Ky$aG~q6K@fqSkVx%1wzJCDFI@U0I10uL!>3}5&|;) zu!<^`B06WRV{=h51uc2+hNOh=Mb!Zy42g-(qj1WqNFKo@14}!{YB8B9r@U-NC+fB{ zDMT{5_{O!|gF8DF7kDPHW-(V^nz~(qz?pK~PZ6{39##=tw_Z|2FVNn9#5m<5kEc%5 zE!587&#W+KSJW*aMJ%^8J(ujKQu&EzIe<@~7WbT@?Da+U7Yml(>;~*}sSuv7?(|_x zDET*81kxB~$pwYR-Rbx%;8KDoqqGT^BAwZ*F3j2nWl5}5A;|Qkqb^R6e2l7Bh^v44 z(U&2ij3uBpYWMj%s%ml7>J}bhI_upGbgM|&@FwmMC|U#6z^6oR)3EWA%6Y;AmNgg4 z+My~(jM-Xy(2rW*n1U)(2&7ekBTlvPKpS=P3{0se9prw(%@rFr1ayeL-Sf3ONAy`+ z%5UPx`1#n%$#}oge@IK;Wi1s%DWuo07J~b)w}U9AA?m$?Eadw(A(FI(L07OmX6yXTw~hlfLzdAo}_Q8zs z=ziNlPBvgJ>ld@2I7#>tOMvkb!LeW?o00frGM=>k%}snL#Y6uINr|+HlxQ>xOR%T~ z)tsCYnA@>o?lSPqe^jTzE(Xi{JByf4`mmfB9*ZAcl$XTA6XE zo9rCyZW|X`FsS>WaM$>(58%J{q#Hl{WN-j$8##c^?B930HFj{Yb@;>MO1U?BjS%2= zOC!#Y74`y3+&YHeG~CJBjzLow+N-4kg8o^pPVMy){A`)jes(d1^6H?|-8OhCon(7j z<{jZ?87JbZ5E7<655sms$!%fQ42I4z)mTT6Mf7w^kDj{}oDou%*LEoIlMzMGE;Qq> z9Ln+8W4bk~%iB4Z$Ngq7x7>!`PKwY=HR+fDRn5W1*FqLI(Wf^Ft ztKqbpzVO@~2cvwA6IYU?t9|KBL`CCX%&!&sL_Jb+$p?~7o{1(`65Z2$sUEqs`Kxl} zY80VCC|1rQ&wX6Rf#pk-RC z2Zn-vUfm@cht_H;B7kw|ELZi48RV6O={S@9nn^c3Lrt_I{oP@345-|E=ypN&{DqO1 zq&u2Q)|N*oge&LUK{Muh-M~zA4B5(77~?wcmr&-L*gb#N$#%i8-DTF==ztKbo&*W9 zoRz2{@0Zo33uPPEkc>V^Wr|wpH^sw2vs$Qkv0e(Sab+_4d2fuAGyE3;e9eNmXZ0>Q zZ$|MA(miBC0`R2wzrC~Dvu2a{|BBH0_r3o9$jJQ1TJZNuP+it`jUBV=R2`{p9>Rzq z*g6CV+oFNSLjy6Q9WPQ)fs~qvTqZyi<31c@l3gzZTq~yY646L2poPHv1LQvDA>Ket zDIaCr&+2&pmX~4lQN&5G=#LX9!Q3{e901VaguX`(^KHjm%Y3|AbR!&o_HyK&K6#dx}Hj ztUX3Dyn9#`5cieE9qqW4DV!Lr8ss$ZAGrOqt?Ee!C>7V1vI?8$L)2Z|UOX@rsDKzv zEsEUWnuZAnQMG|L9iQ-_h~F@0S>mCK-*oA|`YhbLSsojT6v}#$_J9=5b&JjLX{tP5@t0v}N;~jR*{6$PE zI|$8kS1dc;jHeKhnCAh3d_vuxrI2_%Tpc2M7$yC+ zT@R{%wZvI^iqz+ju+puU6vFQ82+uSk+DP<#3B(0*?%I@j+7zPBjJbYB#ZLg_eRch+ z|K%MSlA6ew-&=$`cCmDZBJ7}=b6!3MyM$FT3p#%bY~8O4zBJD}zY3(3EC*^C-V=>B zIa*8h%jbzb3X*(wQfi55&R&4QntcO2M6?AqpV%FPInoe0iV;4XnZZs9+DRQL^a!R0 z-?!W@_!mrSY^1`6VyfD*h!o~b$NEbqlXU?62JQ^+cCu8^oKd*RmJ^!oLL#y!! zlSj=!Z{?hIjzfvNLoiRyfb+Rd@QD#b9-HfRejcWR&2hd8C{u3b3RC!3gYCuIqzYU$ z^dJ;P)ax42hd~)wn=Y!SZxoZiRvnByU{42S*rZV`L#2Z1w6k$k01=Kfk3#*Kd@7$) zeyk*8rHf?aymA2*BJEKXLXVKH$`=5`Vx`%nD>3Xm%$;?426-?@dHSfNN88WUu`*EC zd&-I0#LOIm$!e+y%d0N*VIC)cKQ6zS$-DwtmB)+~j$BG3&sAOZ;SMLu{IV$}H+M?2|ML}jH7K6zxDC}49C zK3RH-ztQ{%WlFgUk;$W7)Iw^3g7j*bigI6oVv}sn!l1C2Y^rPU0E-l=2riWLk zW8zG;HdHXdQlmukHSxKmSH)A-lumKPGgvLvRbXsvn%buxRs=`VLJ+Jq9lxN&?mCgV z>qh@PgzPerqi1m)n9q69&N-GTx=8h@hPl_+ICYFEm2mFid9QC%^K4uqm^UqQ`E0xW zES@8Brj%0((zWz?LvUB3(|-rYx!C4Zx=arN4(-JDK8#ugm{t{BFCVg~*^aBE`>vXG ziw-SsgpW|quXiM{ZAi`%{mH)pFE{s!%UECPXyOi**MAhBXFxMX&{PJAwqZeC;S+>( zQOfiSaQG(`NM?lC`jD-dlb+aF4QE97xPb52;CsDRFZmKeUyos%FW8|mI?&${r7g)V z?`{;5LFFJC5toPMeDz)ehHPXSso-v{B)jvqyGYPOza4I+iqN=(5G!lt2$rV*B7xSU zK9k&`o6Kw0NzS6X4glu?}iZl?Dmr9+}(7{`VC+C{SHL(=leUKkak9vmcg?6bu3q`5aX=Cs)iN{p;>{LHLF;i5}GL z&f*F88ran)c1;lU66miO{SFJFUMvV=;_~`M6HJ>mXMY@LzMhW_c~DN@#z^7OutI^7 z!q?AgrVJgYym1nO2%e(FvI4>3f=CRYGnz<#^N%{(BE{y46N*f6^`vaJv5FMMd5pDU zMg_FFmNYm?@3zN&g>O?JM%q<%g+VkT3`epJ+c&SQW$!@@owNG&m~Y`=6hBcJ-Pm!o zg>UrAi5!A^U+SG&UDiot#D6jCa5uo%{75F39N$LJs&6*OOPH^SKE-!mAQaTDR+;8& zsuarg@s@l}5$ajPj?I->GUy>aYK6uE^Tt`=gOGoc5cLmj6PZ>9`dYnT;Xf7p2+e%@ znmfkC&v@l*9iT=>MjwY}-0OUZgyBd%}`o0%CiA z;MVpA<{-b?cuQg785v!Nyjbk6TMTVW{*rg#@{co3;GTUj)0cl25^b}_l1q7#!i3wLjI%O0uZ?WxWX#W{I*y2 zdQ^u3*ej|Rc zUatCd6BO!Q-avM`wWaR#Y~1+vaDU81f><{`(q{S0P{eXW8x*go!h>C}mO)a!+Zdb4 zC_$rB$>2FD`eTf4JNwt&sfTa#ty3ed@ld3Ak3F9+-+aNcc|%Cv{Oh7kksxFhf*c7gn-#~rIxAga;w3_D)w z401Ces`i=RH9EEgB+^is^p~ER;3myRZ7tvhNiyknCN)EaXymr^-yU~q|38nrow=}G zr|bm&;%W2l3;zMYhCMQNh*`s-BA$mV$AbF=G5eE|;QsK1S3hP;2AsTUk*{Y??|umS zfY-GK!5mFR^CK(nZ;w03e)D3~$T!)u+|+zeEXe6~{06w#_hL`&M!x3iGVEFVwGAEx z_SmL&yo`Hx67iIJbUlE_U9-)wUWem`<-vE0b|c*M7nQOORqI*#r2G2fr6$m3z6Sbb zP!Gp{@wlV^?QzGjuEfE%@asgWrCkt|BY~wABm+Czc66dTp5=t~M59f9gQcD5M(`f- za>9)XN1yR{Th0RzmN({dSdsvdlC5MW^`)yA%^eGPB*2eTEkKsL++M>6bltkdn%>NG zkHHebYv-SM6)IK^fpdr{$^4GJjceKh9E`OcU`V+)e)<=hqM{ zLy9QCwWJ#G|L-%m|M8q1zv{c_n_KA{m|OiBqDB@e1fYPTi9T`-Qj|l?0~nx9U{qg_ z2Aw5O7$D-C-blf1ZBb0wZcS3d&=EN)5ErXq#bQ@jhQy0S{Ah+Q3JhDUR=KS!>aW+n zNw#yNN23e3jpt%up;G@7O zTZG;#cysH$Wu-Ouw?XA3ceAXhUQ|bCnY-o9N!Uu5H~f|&+WCmfm_V4Ty*U27(Bj%t zvQ`M=R_igE=#!m2a&H=@aw(McF^rZ(c8B7z(hskufUq`0((&!tIfXfP zA3jJe+*-A?vtz0@GFo0#p|>-Wh^q_1+WB-OZnl@#AII(&rm2^mb`E7CfZ{cubSUdE z&!@rLxXD2j8$bCKsfl$Nh4@O6=*WuriW1d~%pYjvRB zKD2Z1*gGuZHuFpnXbC92wq9nR*=}a+Tlc^sos)QB;LlvVe z{gKQ*omcrOba%8)mf$>?3Y{s)+0*X2?a2aj;2>(V3O!I$$J4FZOk%K)7-k*#D#+4# zopow%Z{E~qlhA)%t6BVFm@NfB*%|<4Nx(1q_tFvn_%(kur~VtJ0mgg(g6XP%U^)^1 zdnZ}|lW^_6%6xKUAx&!R$L7L|GS^}JBEx88mzv(%nmc zX4yOp{_mR?KH8T$iv89|p<|cUs7Ox`+6B_O84U`u1*Fz3@88G54q*zuzUm=?dDh`c zg!g%;#(Fx(?z4C7EXur3$(H9nz24q3LaYY~XeqK7jzBAH>0<^zJ)+d?{?cnb{&_)@ zW=txq%7V*6)X2!rb4&T-hBv!40J()|xMvzP*d3uDKQh$7n2J{Li|n5sv^J7dFd10o z*G+f^?rd?feKrDht5@GtDr%%%wL(He%={FQs(L(oHm^VDsb`29V+!c&AF3~|uVR3C=3uQiU8`n^)U z@dX_{ryb%}2z0i^@5VXY`{~RWR1^c3)&opmd5Od^%29HC(dpiY1LPlpqGF7JR$L<5 zxgQ|$gpF6r*iR(nJ^ayktFTKxAfxNvmV*ksJILn%-q<$!3C&-Q{k2Xkh3~I`6y5xD zX-n|&6m9J7i>}t7mnIKYJZ+-YLm`IYa5s!nz&~s^)1IYzT|u<#6x>So%x)G-r2uYV3|c_sF`W(_${YA!;lLFd9{igenExM<1AoK8_`lc> z{}eR*qb>d4$blLh5XM%=dfy0Dv@Qm4N572qB>sBLnyUM)D}0eL*xzXPyv$Z=d;w~* zEc5_!H*>Poe|>!o*704@_I>s6Oz2HIVP1BLdKz4VyGR7+WvSJNDy=6KRKumIf!Bcw z92Wsm6*N>Q%s{j4#S@O10KIJcT24kKz(6L7SYy&uOUy5(n&(Jqo*W~jXfX>3w122u z;tz5lN!UNgfnFqMelJ9y3u;$}BO*8lqJ{W_C& zJi9on02A9@4c@diH6oAxuKXXgS3Yc*O4{KkdgU!koo+iQWWpZ+kG{W2l|(Hz zfW8A>HWT1O|L;p?|Mg`%{?DiVXDaS1%{PYHUbej9AUbIMjAUWT^CE>v>dJ4h|N1`8g_kL6g`>0b-X}VXTIaXXg-G{&Slyuda5wX*L3w z1_IJ|Ar=1%E>vDAZdj5bN<0O+bIjsUvu_*x_#A4)JmRnHFiu<9b+mct+(DaL-dpF^ zO0u%?H8vV+6E@+x1Wq*$%S!d)U`V;OP z^LW3NT;;cOT~-rtLrgFB2-wQPfgYf9ZDOb!UxX3~tLDSl)pFBf7Uy1 zKMCM7zg<88s|Q-2F!+BqI}PxFW+(j5W`_bxN}ZADx6SaH!&FLV@oxGtQI9rUjX_i0zw^A=i)jU0Y@QX*Ziof_zqO%jSw8cf6Bp&55l3lkrMh^DG79xx6o;3~$=US#8dDxy11 zJWFN9vz*NdhruXCM<$L1 zDPBp&L=YmUF2!}uO@3lT?B1@8v8XPgd;RO$96W`98|_A<+Gp?%d=X&Uip>>SnUy!S zzrW1V9ZJVa|9*B06rL7{0_?EdW@oDRV}e0Lex=6Lj0L+b1Ad z*EN{pw0236tJ-J@GUt#JWq@J9oub_+l^ur{`b~Rs;tH}k{D#xb(7?;{`K(uoa%8~L z;kE~^b~wllBlPAGwigy+Jg;{&ZhJ8+&iuL2;gqUgmruSof|(yvH!nvCx#Yv7Gusxy z6;BTnMBN*&{k9KyBufr^UHY4z<&@>F8y2AvDCGsU{&KWMW->#pR`BY}Hx~$BGfzF7 z^2?KT>D~k3j}ku!9)KZ#psz>xckbWmQPMCX*Wx-UT`6^Z4p7K*Nv)csFMl%@OZe2Q zRS5utIsgnZ{}CAe8wdJ^PUf~Y|4V83-`oG-cwLx5%)I4OmHGcdL?_Kk-G1inKE~SY z)Y*kuLsYz{!Ao?6XWwI%O7NM_M@u2bS9*pn@6N8Vk=7%Yx>KH~K^1Wu@ZX4lH5{Tm zS7c+=2GUPgXqF2JN*W0k(Sr29@GYEhtN<^XUOUZ6;mJ@5{EZ09HBqn}OeA&;EZd5@O-?L7yfuR4AVV1e9_LR>K-r1$`!sRJ#Wyqehe>Oz9{8y*>s*|nni5x zSR7~=!?m6{B$-=ya7X$Z{A?_dq;k`J&Z%+9mdcrKZ3%UsP18pV+4nF}JwIzFFBi>C z0)NqQY@gCxrCRZ4#ZYLb)Xs>v>-`Z%UkcsZo{M> z5p68IVx`AyP3~Fe$f^o(Sac>lF#?HlXr->GLg>hU@Bb;S?Q;}sX612@Hiw~r7-LSk zH{IkCz@3z0{o{$aDbJqkfuAF{2R9LlIHZ!r_0xmiuMv-%;Lf-}1=R@MdXBc`B&?Y- z&7_`Z3d-Y34i6N9^80mnvUYyXTtnq)`_d_%6*7_Tm0aoEqcY22#C7U1!&CPkPcJtb z!DPyM5zSu?@!>WQ9fLjSSbg9Vf_F=L3n`r(2HKomjWvBR4%_xCtmNsgxtGk6;)-&- zPzs-5JF`v0aFEPm1oxTJHr#il_o6A_5754U$w|oO))r?p5{X?m7JkLscgyY)w8C;Y zHEm(JiD`sf{^FBzs0ovb+8Gb5>T<=1svC6J{-w_F$kU^wkP*)GjQc(-@jOl#lL>xi zfpq3?YGzy%m4@H;^GSda;NOp5`Q0e}H!A*C9sU=2kPgTHM;;{iS9uWrZ+Q@u!xlgu zbgGY>!c2+dk(ch{HbPPpVU)^{gDTWXJP&#Iq0=rwmR5i0Sjh2P4;pZBq#VY)03XBl zjYyzT*K>Z%aavjNAuF0FiL^+cVkJ!MyL?JwYiCWjGndWq zey3}0iT&C|mla1l+-EIXO+g$uagQ}`taH~*&x4L>*_6+-Xs9Bon_)*6?9+$R!| z8xh1n!5Z~`#u&6QqzJ|>iX2>$6GG0IKITgx%Xe=Rx4c@+Nmhv)eg-OqtS}wWg7O3g0rh^*eO$ zIA#A3zFEut7QQV();he+AIg>M^;bIy+5)`Vz9|Y+8cYFVg=Q4YjJd>J(*T}1FF_)q zK<-l|M}HG>0#mD4m;uy5mH=YE;D7YBcXZNsa{eEm_)68aGJsCV`%>L%HxPP2VJbqQ zgi?tC3UY>8l1e}QvlHv&Kw2rL=oKyi%x|C{+l07iV%5HE5z?|0PHo*3yIUJ{`QvW+55`9(#`dI@Lr z@)Kj>*^8jZDUqP_YD1FphFSDkqv#}Vb(JB2sq-rV?%u-*r3iFX5XMsKJ7z#n^DSgC z=G362p_-!#_22q~4{DiCJ_iT(>cRXZr&&tl=BIt4ju@WODWe{iP&vRA$%YGw4)M#_ zh|Euvg!bM{A{@4#xTFKC9h6qoSh+_<73*R9o~hGlq;tQMXxbp>d=ZuV*2d4kuy}YH zb6O8H#;~7r7IA|jKed>X_ZG$=K&17(6w!>2#y3d-C`OYpv3p!*`lA8< z>#xME>EpULyaorzs3ygQgET{P$F|iPk0LqSIhrszz~7fH)}qYf8|!YHK_<0; z5C{@z`=K;MqpAcQ=Q(W)O04U3DBh=?7(&Qub4u^w)5qMl<}Eze&hZ30Jug>2vG%2Yi(G2oSm^BifqQ;prn&(Jrb-j1k-ab@Tc0RXrhCd+5F1D^w)RUvM>rwIX15%cCQlu5aul|lMOqE5>#0$)?SHzNuxP3xsbzbo;;8J#vQ=VWyb^_JY3IDqaT`|nm^9S z%1JP73?^wqyhB!lYAEmySL>Leb+PlX123iSRQN2Ld6ADF=J%b=jt50o^0oe`uHdwL z59#_dvi7>q3Haf$T+lS=a-J~!-~HUS-$|~I0o7?AP@VYxBNRL7oBq$aMb;7!sn>a` z4#%yL8$MmoOGeaUZVpZ63~177=ue+G(sUFeVB_ZW=(*54T=SKpfxgC z6g6cvT{VPG2rMQ=pAQNJi#L51H03ll#`fRqioOGjB7wx`Ywcflxr?4)Z>UuN+QI;x z(gP;*jZ{id_LDqI63_np+rm7ALS9Ewn^KJi$3|M1i<7Uzs{gGCReaJQkGB)MQC24R zWN@S?`DZ}3kqaasTyIf7)xqq6T$m~JA#!3|*16HSBv3s@63WF(%2bH|%c=o#S;Z)JabaCaemLc>TBt~wh zIAxYgUrn$&kC7Qpgv00WF?g>U&l^|Q{r*yBMz&E_dZem5kYCzTBr}{`M|4*9TgC@E z(wzhE_$I}?i4DmoLUBTB3zux!D;iDRGKb6`y;TNCvtGJJ9f66w1s#;3)y*o0-tP=2 zvRGRO`PS*Z2(Kd_*t$#We3&4;GVD6FpPch{9&rR?DsEA1_Yroe3-T($d_W;DwH-366DeNY5 zs&BL0L3)wXt3OrdX|SZUey;)Iyb|iCCK*Pf4>HrZxYIR9L78;M2l;kF)Tl-3+6j0( z?wwul-`6Ich3UmoVk<0nIFzAVKWT>(me56F72JiEUotHE1>KhP<>lwIJ0{760hh)KW92ApZdW%W+{Tv7z|H%N-^I^| z@>G3Nhx7xRk#DTp8E+GpPZgBAY1EkZI1b^k-r8T#I7)yDX9FScV(#=zGk$qLu$5pfM$5;DAuQAeP~Ba}5ZUTf-wzdB!o zX_5n}pcgIemi9gq-)kUc-+l z{BFf_StPe16rzySR2TKqo1lv?zpDCr_pz<0o9SW48nb1{ZCPh@%X@=Puo0LC!SRDM zw8&za4=n{zO>DFPb*$2pP5J5k+v!w&KA-atjcA|_M6}IK`0xh?H{T^{GwC#Oc8>^| z=S^R|B%b`)Ikj{xS23q^%QwBTV8Yh&Z|Jt*-(R-lvGoH5)y7v{fVVlWqTA3KrRZ{Aw-JSqaP}GnRrmPE9{Xlr?TfYM znt0~>(huK!M1BuGzP`&IqJO9&taAu+9{e4AXcE!qRq4Av?WXS4HCO5aV33c%L|ey~V?AwKJ#S&o3~at`MQ4$HhI^73;Mg1VfzsUG=|HI?mAIx@Tj5 z%O*6A3H%X3Z+H;V^EtI&gLN5q&kw_LncSSah#}Qo)1L=g!>#@f(x--OORT?&0fv&4O)7ns)8YAfv-=^glL8U5o2@^8@uedz~bFvg@4ZxYS3 zkP!_jC0Y%gcSaL7X5XGo? zEDX7_1aK51@@Y&2$lA{6^l(7KF*RWhUJvICh(3XYQ0!K2$^rJ`+_y56a{>a1WrrWf zZ8BMgg5s=rMR4C<=*yor2qWkggN6<^OLKSzLP>PRNFyv+y^2z-p+N>3tVxsqiw@M||lm4oQb7Ym}9-vSX;|Y@>U5D4-Om!%)BP1Sbpn z!1UUW$c$7rAg5cQbmAoGapmL4iQZ57Vz zTRDz%#Oz)U18UY#lgUjKA;K)3Y2BDh8E^iPR^HW4yK2x0-|okazmIxMkgOcPYoz2gmS}<)N1`8!C3uRdYz9);GzW|1X zl9QAkdt?u6K-QD;Jz)M{Yf4 zOoDbmR{dGcaA((H7)H?)W^jHC%wObtz>LIvNIAs%0poS7WzE)i+3yiodHYD%9eJ;Q zaDj1xizq93z7;8`#;h%r{VnsMAV6R*3FeKHT2rohi5>3Lm9fZjC*gH zCPOpC=~27l@B!CzQxSbn-Mg%`u%&lf1|6YoY33|k6-b_X0F~aW1kKkcJ7J7}!(9GW zqhe>rij_)!uiw?=sTP`}U4}$^KY2F6@CVqh{95zm3+b$1^U2~sTAKO06qki<01qVz zXzuQXM9E~%;WKUeR9#BhhXk{uNCQ|gfWs)`Qe0hUwHuBrXHE0LMVZPL8^LcwbQXzS zet~w9Yy^FbWMdt8#Kjos1B`nHLv{{(%895)QCKq(cf0qrMgxIF5w6-(!F7GJMYb*g z)4*)>xqN~XyTg{NoS#);@M=x_K~&?F#?@I1QhnKKV5NDK=u{y}Rf~Ql#Y(fh*(fhUE`Z(_ zeSoc6(3@PQ%4POdVGkD;B{INUYRlZR4!ObjA@`A!&g02CQR5AO6RC)&oN+~7J{VMF zrfgV3H$&U>IR>dv+)-rqa}rk0@SxOWmu)D9iM4s5YB>jdPGjY9?&D9Y@-%j^T{}S_ z^5U8&JpP-Yv`9aTkoEUIL^%=w0PTNqr~WYx{Ju_wDpuj^tO%c1I{5E}bSAbL#=+$hdehveb-Pkp*))2T+qGd2z-^v_d8@>AW6QQS{f@nj=G5g&Nt zjCH|@q`5A)5Ed=cySsT5U374-y12N#MrVt!67nZYNqu(lMQCu0wDKlv5P+MNnaoT@ z5ROXZuPHtV{4B}LEWk^$n55gBP#UP*Ic@1xp~q6)_5M(W0hf!7hXe2a=#C9@^b1n} z9mZQafbV?BQ7(8|QuGs6(ay@kWxkWm2qDUi^!elDw}ZU>y|=N8ih6)>@vKJ8+4n{y z#$3`6t5KNFC{lf~vS?(UV+NKI?cMT+>S)8>41A7JX*(N0L?_zM_CwoyBfeVEy6KGe zg%hCNGIEB??4}m={Kekx>)G?^?*0AwSOIZvo*l0^6QB*T$s`lN6kt!^mM@%$r$%+- z6hf)?Vv08>${fPdw_ZtS1-B}3%v5(qp1SF}Z=!2mjUzRUXrv#D>HsioPyRuRTOHi; zu0Xf?jMvy zRR)ZYSV8JZA9`2TOH#c>%0!6c*VuH+A(05|7Bq8)xLNFJg&#?*ZlY)XUV#<;!>2$G zM&h14v!XE80^RDG=`iTkAHhpmR>~q8He#$_U4pq%xA4}{M4=EX!*lGZrOS8|276G; zly1txRZHSLBn*XVPWLH-g0DPzOtAz0hmJt!$InH+rE@jAzJtFc-l-8NczG_{zqLjK z?5-V$$!DF9yN!Xs;60n-G9BECH@M)iJnC5(7<7z2W z6`Vt$D%+LnD3rnr{s^AxJu8ep6L!Yi11}%W#k&qrSA0Wj3#_QRGzRaqSP>b_0}I|? z@aa}i2U}E~w4SMZizmDu%SLpXt@l18CtQ|GleBK_c6DNRYCjvAJ#>)?0d5V*YTdm| z9wg23u`e0B-H6>a=}}H`D3QQC#uCXpq#sKYC_XjKQD$*4J%ptj=N#2f8ppoUK9+Zz z*VGa(0B`a++~DfFJ&zt3>tYaD2Fl8OomgO8s%hC2Dyq&*&7BDo+XXD$zZkK%3&3(3 zKU%z7Y(=8cdK}-rF)P2Y7=N;+ECVRTYWyMC7>ktpUrx+QxoG|@~E zA@pX55rccHrK6o((UmbEb$0cRL(Z-`J)0xBjysQ$tI}-ALJ1>v_ykg1#2yhs<1M_f z2Z?FyC@IU#>7D+=D$@b9q0&E}{m_!Aq9e4dhOW!F(*UTMzt@ z#4s|~Kf}GZP#w`&4*{s(u_(+U_W5tjT8mV^M$&i8>iPcu=YGlmGpsVQcKqhebsXJn z{|fgINA^Pb(;^67zl06O|8BySHO*b%&avM|poEv6JSo30j?{V#tAI zNO9B307tYLQsprta3zTS%&FOWuH00n9Bmi4x?%7yDNA~i9((=pgGTYsc7gE3K7VL^b!V4zCaVU=zV(rmTDGMHJG*|pHpt1(g zVy<8duczx$NCSEHg%EKZRwP{!p+-#{G5IY$MIHn~-2!8-0e_=ooJ2v@CN8s7`@CBR z+@fo;PlbTCX9W4r_85q)5=8p*rQ7eYN8RV8&Ju-&VL2?&+jU!eqAs))3&-5|Ei*1 z%xs&#UPLdVPSNiDNaPOebnwb!zUeePgM#5XMWxg!#dgx7D}}}G>l6Mc=0@(f1}=5R z-Z@D+WqP+<6!{>1X;)rWx_HK4P~q(-@!!;N5|i^^1-$^cC0D~I7Bt=qtiX@wh(Nf! z#?NHpn{ln=0YIiqNX-&B(ZE|rfLFEbJ%ao6me&X(&%CI@hnTBZGyrzqk;-kch&)+#^F71eNr&1%9}4D_CUz^v3tUYloj)rw6^uS==SK!AMmsl{Ks z1|u%UD>xs)VVtCn08Pw$N0{Qsj#2{3hQYikLA@tt zPM}5^@GwfeS_nnIAE`pJ*S%GEtsNOCj9gbp=8&9W((arYT*zvVMe({!w2`EAG36u? za-b+QW+Ae)-79J^TTx|_MN>s+j{1#HWLzLB40B0uPazJ`h)CZ>?DJ(i7po6lG@;qv zx(4MFV0rVkCWpz4I!XfD=zXM{?JImum0^~$4et+Utl;D?rt4o2&W{sETP{=SAt>e0^@qlFOCYplO{ahV zUZPidR_`(SsTUblNy_LsQ!1sbuT(n7SK zAj-o2l0r|+{uHoCrVMA*V+v%y0rlx2ClN=r=M4~>n;+)4QE)M?|7Gr^)`P7_#MB$` z0Vz*){lZy|2&Zq^(th3p$d~LogRS z58r-&2dv`nuh9RG!1a$9_Wwoff2;{12t7H3;s4(?A!>EV2978E6G0#`4f@cX%gll9 z*L&A{uPvlGb>yH1o7NpN9DuA@x_$nMD=CGLfg)M+!`n@>oj7={MHAjp!y`nRk`9P6 zZs_57GJ9l~t8*DT9d-pzTYWemWPOnGe?metiyYaY7KWI=Rz| z03`Z2lgKD?%Ev|WQ59RiP3$n8%fnVg4kfV!V_0mDeriU}*$?g3%LHr!THwkPXo9bh7xiyB0(#EVuaf3AeF-dfi0l~!0v++Zm}9xR(wuF2Awv#p?WUxPg<(w?HDxG>zOP785Amr!Rn0Xug41o)v>vuRBX1x2BuC0ZpHl5LU z#R+R7hzmJ=TFeRJ-mO}F%&}p6sgLk23~srt*$U7)FXn#@JR~z=+b@m5p&bNJ_j@<7 z9E8q8X}|9MXG^fGhR)2?4DOtxrNN_CW+qCn_?H|YrPD(VlHlhZiiDGIm(gEB4zK!r zPJ}#N1r8AC)Ef{~DS2Ux)eMIMGU_P4k6sY1Qpw)`4&m1cB4YnwmL+ zb9jDoXH>&)W@4f#e^oLgHADijLfeh_8LaC!N|=1@bc`3_w4}FlUHWFBuC=qnk>~cy z)V3kPGs*&`!6{~q*-)V0?0LT4^U3MW?7c~_j3=w833r4srk79vJdMJT0xki8QZ>sz zs0k+KBIG1_JS2VtcnN{vWAOy!}*-t6&}LSQGp@%|)@0vvHKYVn{Jt$c;n`eO>qYlxAe7Z9sRKWEV$R zzQ!6<=OxSX!MCKTgS|7E6h;YiSZ`FmY|EAup#FWe>_l45{4jEMSONcgK&@Bb0}>={ zAPTyr`DjEBeTQ+T4ekz7G3mFo?Ey2Ivm^*rb>L>g-M|L!aAuCSE#lyi;;@}PXN7G0 ztO`X4E?=u(ir2XRS~5h-^KA}&ze*(E6W{;5WoqYSWbgLRcj<4BNAdD+%k<;A7~#{% z{}>#?u;H&k*sAHbK^Vqz5(k~g9i^MDxZdQal}s(m3G=Ig!KF5zcfQuBJte7h6P>`m zF#FTrCyGUFG)Z&;G#5RD5?UFG(c|%*mEGO``Q&(LE-{`F=C5mQi zhFq7|Twc5u=!v@**LA4+sSsWansFZGcNvHF2{Jl;r|oUFHID5@dYvY7$1w+vdsz8C zTM_e4Z1Zp_}hbvM%!7G82lP?HF~y4?6Cm z7^rk9P8qKmwVo3Aym)moWXCN3dNJBgFn@r5*U~UB|4r}Ue_xFMcRv!9H={Nf{|bkz z?vfy`nx2B@i2AF~3hm_ynHG!Estc_S%sYwgE&Ra~Rw8bDDAT-wIfP8=6Sp!;R6nsSNicHriyC~1);l0Z?a$eB{V@hhL=G9Q*Zia+)1TUZP>6VT1G47G1t9ZzeeqE{3J;~ z3QaK7$6^Edx$N{P;Z^um;WLZ=+Uc$HRkV$e;hIbHxc-`P;`0dlJwQu-WP5L$tAl`>^#ui%VJ<0|383-Xwydks?0Je37?EyQ@rkk3Q zqD!35O#cL)2O2-0IGsjCRs@0^=zp!cx{qtp1k-W|XvZZ5dnCR(r<(Nve#aK{F4S4> zj`l;iKHs;2h~5wY@LnD(W?19!|~UxjC^!o{3Z-)Fo%rDpj4eNphvXN zbtUt>Hm-C~MT{DMf?W(1eLe8@Cfzf)F=Vec^_FOInVaodKY*3`%@3m=0eq^Y=@JVr zBb9&38k-=~vB?tFPrp!6ELFZbbfLAG+MBT?WRa9vt0ln)z=r>Y`y$o_Vob+Dj%e(@ zG9+&6N8T|+d7x8D=}CMsgY#|?y%>u}+9j+{^fKNcsXrn!W72YDS{nGg6D3{6zDLUz z>G`@*qpNOQLI)Riu;F89)y7sY6VXI1Ny%Es+?{!n^}d{%tkY0^)#T*q2BUkLzvTpZ zr+OCeTc~4_OM+jbw(;2VS`c}4lk=j6k)hroMK$qsc3Hlb%}D){lsDZLfnB#0JXE4! zKsI+?j!OJwF%9JAU|3r`5m>no#x=9ZttTy{92EQP2IU@s7H-Y|=-uNO;|kcyz2 z%qf<&lgA^IRn!^v^*=JO7%FF()oEgLV&iS}IGMAdY6q$V{($Pvd*0KRL_ZbM`Y2=CMHq4IZ=AJ1t~>8F(fSl=%IKIF`%1wjkABpiEz|JMLBX_^ZY^_@cNe^bZ*xsMd#5~27* zfb-Dd-Xmm7Le`Kz`(APB+MD*BE*|=W2eiB0?v0Nw(*z-<*q}V4*g|XQ#LWVpiSTdn z30~SGUH5W6iF&Kw7x+Bra%*GvJ*O0u`+ztJ=!CfivecjM0?`gac4%jO&)9~=a15mR zS#A}A=IQ-t%h19)s-U56{cLPZT*_$@=_X+FqumSD$1l?1*mL$-Pf}@Wc@ALe^o28xk0Q(;3PSA}nA2NYi{e+AuY@?G+#Szr+vT=!h#`g|~zGZnM zGhQX7Lr&I*db+^ z&i;L#-i|;kN$2>>_g4~Qg1_T9cHv38IFpcmkguk_wuuRZ;nbi^;=MRj5Q<4-1VD4v zb=L`}cf%iq*L9y)-AOPY5G6jQJ$4#^&Y<%87?SGC%c&#duagpNA*~_Jp%rW?4%nMG z^C5*&2Z}r!$T4o-BMSu3O7*yXY7zregOj`=j2_@IRN+oFi4o)aGdny-a(<{vy>~pk zIR@_&Vsa_lF-QzhP{R>$0Oy0NSj4tPDkS7@+CCVD!xSVd|FnRV@S=l~mUwR=o&v3Z zcSJaoR3bu(;!jLK+hG3eUc$O~EIMXx%Gign{?LbONFqQp0eMsEX62+ty+Llix}DyA zlquHBMqOkZq&Ve%JfyZSopB!dp7SA3!?*d8WY$pkWv*wJeeJ|leF5C2B4Z2%LIGM z`z$V8S5bB1Yy-w3b9)ZN#n|-aNfjps)z2=X>rR6#z15B=aF#yO8BkoiVhBRF?x3WQXb4O&#T~mY1TB z9Re6E!?DMutl)qJ6w`c(kR9tIwQ1e}wQuY!8oie}Pu{FS*AO@5oE(fx8Fmt2CxuYU z44|xLrQgh)?r` z5%ALg%qjft;(G-N2W?WbMB)Md5XOm%ll)jYR|fAVF!?r9Kf;!8D8Wc3>yHyvN3iKt z`+ZQBcjzE^xs`8^n!8#?ux;=&*M!)}C_tXFz@)M^L6dO^Q*9;=k5X2D3AvqCzcq(w z`iH>1^`#@TgxGycpC-bVt8DKCKMqS2zRcVnmxsGM{rn3gQ0nAN!zkO0iFd%%YTZQ9 zXX$`F`NLE#u6x!~O}cTK0e*}D<1GSb*L8VwI?J~Rzw!P05xwvkO{4Pl!s8KB#Yb+{ z0_=sR^{3z&oc5J$>%=|8_bko5+8WWaaZ1!nkwx@t-r}ZCd0E#npL-|^@(%=3-m!#O z0BjYmd<{AZXwZ8rIUPU$UA?WJ^aL76n-VU7S>={XUuij-pnPh)9l|3Ek!|sZGh4h4 z#aJjn8&*JZ1rgJ>97Rsci-GJm5RXNUzz6VZr@y+5#|_!@pNIB*8Xlfcm>6RnANL;w zPLa&ryhq z;1i4+jvIe$n=~BO)pi7rN3l%N|LTQ278_I(YAL`&O_)`j!dEN+SN3ReK%I#jJ7r-- zM=<`aF#2p>#>KCJJ%THibdty$S%A3`LTTFaQC8{CHXJD13EfjOS@y9FA@b0mPWXB|i)oTr)( zj*aT_WYR~cp~!5gG*iUh{aKw{&7bVBuKr7Q^bEOCV*pL}3R^?x*obMTM-}x4n1Lm1 zL}GaQWKtclf;o<*HX(=uL2`#<$HkI>!yUSyc1=YlgxBOss;EN>t=Hy+iAj!PR#el7 zWMsT{5r@|L5P7+B74I4T*j|_tpOmp7G)(ZlV!B#gkTLuEfM(Qa(+L231ZhZSHy-T? zd$T`WI(6p^7;HXv&PQ81T<%)Q^@(K0)=%7ZFO0bApdo;YLRx@e<_KPFSIKXgZ(!04 zhAYS1OJNE1y!MPAz=xB^LBCyEu86s8FQvT1e<47fT(-78$^0RhQZ&bL)cET=pVrS}>i;gDQSzz$9NZ|-@v7-K$%h6_W==q9f$ZT113P*v&R;p$0{fF`6z2rDP)+RR zGR8wq%&6W<;&I?XCnc=T{57dIH>;Y?fg}cE=fPfpL35-NSZTKM6R?%QPp6d2RDOuD z=3rB{jxdfFDwk~J8nCTT;T)lOpzBEt!r}8Mt;>QmRk9AhleY;fKs$N`akb1%ut21> z<#hkRTuo z@ul4+82jzY`qqd##x5(JSJO{uS=9zWez{>BF9d31KxRdHChjJX*naWe@CvE3MS8$- zy0!JHVzdPp_EXZ`jj4FN zHet%%2E{KTl~7b_`jZV6%ByHJI|M+d3q{7yhU-Htl*{RLh7{)~DQsi!6>?gY{%k8` zGqDK#6=FTlT+$_lx^&U+90u_QAtX?#PKbGnX=j12G_RubSi^UXJ#8V|se1qGS7SN@ zpDj}a6pOl4-;S$<$jhth5alv3t+e4_(bk3o8t3Fbh6p#rt0FBQIA6}aCaz;JdRJf^mGrZB{DC0VV?aQD}9i3Q6O`MLH;(}^SKk&p^>JB_4q<&Pz#fF51yW8#C z51J!8@Wj0fcGj?cNTkV99?_4K5NGEkc>v?- zSkH3HV&SW$Z|6yi;CIxtyrcX{_aO|3pvfS`sZ*pBxKb*s$B1=1ea#{;;qqLvb~7@h^<<8ZF7Eq+4DXQx#Zc#8NqT^b+}# zqA8opkl-g2!Sp%wpKi9w=`@7{9U+krNd8IW7*KJ>Z80;RfD7JzHM+uNGZMzu-gm)C>>fM_J z3-{irR<|^hM;*)2=&2q}lgI7M;tF4fk*>Y4E(*y^v|vLn;UXG^r(%3q#Eo4bMvuWu zu%VJK0Ees42&q9TM>92R3C8JYcH#wPit;@2&4)`sKrUoC*D=*J(#g>+Lo&Jmn<2ur zp1Qtt!mkk}H^43<{7;MocVI+I42j(Oi$}$>s7dpp!rc_JOQ%q#CSnhF@rc>01mCp& z@pKbV>*#uDP5;3#HuUuoREPYZNTco*k|})nz{a?#H%`%EFKdb&kA~56e+qh&jWKh1 zv#28_Obn%q@dBD%@wD z{}GShoM;r&a=TATFa3jfjawmr)$(ZaBMWjtglb+w3QKlW9t{xiR(Tpd2kQ zPPl5^*tKH}SoiuUYsGaZ0Kealau5^2MF+m~#CF-7^)~En3Tu}unE8fHr6NKhZhc{S zXyECQdtg4NpT8|pz+ks-fmlTY28Rb#+uO)Op89LVhI&Pd9Lf{eVEE-7ek5vPrA$=! z*MQIk$EB96S4+eL!!FZ9gg1^;$BIj`7**MY=3BfoHTFH66IgiAdn|;OG3oHDnMC)U z8iEz(WN;|NK3Pe1etnTCigu)lmCnp9Yg9&!{pQWa_@Gorx6m;(Lud&C7R#k)vW0;- z`>32T96ECiUFsuNN_Wh?N&1jnXNkwM+f-UQ*wO2&nAP>*6kS8#5`zRgf=5#^6Z&wz zfmlz+PUO?#S)u!tVzq|&BQv`qPB-<*7w$R+KyrRH%Z&fgMI}O5Jq`wXIbtWlwl#^y z3W&Ib$uIv+;+ImT<(xA@OhO&nYC!00b)ra{x9&;rV=9SO6x3%d>x zpcOd}CMdBP=U^MXJm6EKtDZcrKtm@1T=c=YIt1B4y~#hg=~B$b41@H z*MIKm;b{8Z9{MYwSg5=iw!w_j^`royv$|jrmo5*ciIj$BANxQM&(A{y z)`tLOr4Esc{{6(@8X(shj#@WW<9%nihO0?F#ti9czcD4gC#um?E{u#cYQzZAAc%~l zQ*HWeNbPZG#UacdPvKg=N$qj(35tO3>axnLu+)fodsHy-OjHo!tYMGt82#d|AIX@N%acJhsA2@IXO??L#2qU>G8(b=Beim`SCKTJaNnANAX+5p-0)`3K> z>=j}`+Pn5ypMnsJ)cV-W|DeP94LfOlc;V_k7*askEG-Jq-8mvEuj%=k;zxae#(j-E z-D!H4>5PTH%DCb4j4?cWX?+D9bl<6KFWIn1ImU-P`yk}LCTeq>V>tA=*^74tG<@QS zRv)gvHUjnhNe38>zWJ>c={s5e3J(&}eP9Iq1z>4%hg_!9_ovkpR~qPL4rP79xbG~} zQeu$|Bg$@I`;Xnq=gih8bHW|as0;fJMM*9J_@2d!w00A9TL8c%m*?I7EQ`)|D|BV! z`&BsyHwIydveJP#LsowFE}Q$qNlCaQ7yM63mUN*k8di9=nDRz zzi${eh*cZ*#?Z0JA+ID!)$7zMAuI>{k~~?e#U0wlHa+`nw224{u~Jf1o?PPc;y4nt z#JB<}wcZtuGXn!sX}&dggQ?UitgkE-vIs0*G^o)V8_PU~XNu^LOUyF&%MqK*j<4ry z6iVj@A7eH>M|r}Q^o)QvHOGQ)FrBDqb3v=@r7F7M<@*Q;v0?fd1RUJc(+RloxnJj{ zItuk+B6j*~f6F&;FJw=*#?Txs^?KLX=ZD;v!_T?9h%J9EH9=)3_7S4sm(U_<+lmM< z8%4dGc4;KENgBi9xAtH8niRclMKHN*t$JlaX~WG|y{z1U-Uvj|23FrgD$0exJg(n! zB;0@It9$;e936SI06$p7S&j1FTJS`x=`~K7aPks2wq8QUTl%00IQwpq1Sg;p0D4U* zWYZ=|{Q`k_26yyFKK@^ssEZ$^y8E5}jUx&GK#4d2z_%ym|EQFj7+D+H>p9xk(^1h; z(|&&pzeT#J%&d)VXrzP``2_hC`7Slj?Kgy-Kc|aN;(RDa5q2hT15t~`lRB^~snU(e zr3)_>5Yl>MXz6+=eRCP#B#0&--47EDLld1k!i*}loa4$ABSoXw_8w7tRBoV&qGKFR z!LXX~Pd5j)7SyTji)OuEA5I;*zJIM=i(RZC7ECT$vW((y|y>MAUu-<001-SRDTq#O#0 z`E*)H-DB}rEk|NKRnU^ZZ`vOQlU}v2GF^r{Y6P^x@2NvqQk7ryN+$T z9td|SY}x?bj_e2^r&*s6{t&B1Gy9n{Z+W!NUz}5wd(4LWD3ar-&Sg^0_0{);;tKKE4P z0{LkG6zg8E1O15_AoSRGg!C5A8|%7%IzOK21TGo{@dwa!&c{I%s~W1{mt!9?P>>a1 zE#b+A|2D8Ifd9@e@4z}Ek_fEti_>#ZrtiK09)payVc3_q=U4LxuII|T38D{d=N~)T z_ipF`7gOqIdlVfPh7!!<=Zy~*&tFrt7wz`>(UmZOcBGqvD2 zucQ_&6TvP47@=RtflhTKb0+3(IHo#6%)0bDem{vh`_!eE)M6l6f=ONWOvuPwyZkpu zs2YC6aM-RyXZJdn1zN>Qg4Y}nn&z3zI7m=S#%N#kws4ey-}b640wh1(dM(vm|FrUL zE7I_dzv{hk$+dw;X9Cx!9e8$q$8=;1C>}Y%3co$50?6{XWtag}Es8sRe$EKFHbI3| z;TO0%4J%?6xa|2!)xgsGt46@9D^MG^H{|j;1U*>Mh4)%+(pSk9W_<8Eu}QCtiIb#k zorrZKxikK8?`oJ!y(hUY@bx#y@4|?{0&M8)5Vq0IDTp#$XQRoSE3d*-T%t||hW^arb#!=B^;R70 z*>hV87Nh`e{v*GeLd?s^YZgTG#Y#5`wJZwl-;*YgmxumT8)lw*h`I`gA3=uRApQn$ zRIv5UsZ%Ff1@6Sk`SgGF3=stFmDbTG*kOz%IcOVZ7jS>2%T;`l{D`2slwc&~U7znw zwfa!JJUy0ljbX5Zjo2aGrR8qT+%eH%e0RqH-D&J@|Dd_mB{=6g_;J!Jn!if<3RT); z3DY0*d9h1~XhRPWBa?4c91Yd6_nW>x7&n9+KmfBlcUeBE(vEj zLvVrzR@?p)!LIH=zJPcM{mBDu4!;4aH~=v&lE85+#~oyHhRR-cLh-&lcokx!`Ala9 z=qVQfKj;S9OV$^VK^{GFoFe+(isdG5`dUXvg-F%UHfZ${vwce5rnJ#)5tglqGbt*g&|fmy3$+bGo8MRv zc_yrJuSy&T#^%j(j}c!fB2aw#ci{jRmSNP1JdISQ8Fi8Jq3;z3R1t#Kc26s|YU2HS zjCPfH=GrC`oUzmK?tzT${80vo_=IRDLxtQQFZaW*zEfgkB@c=s7)!&(xZV zf)e_b5c}f|fQXbPz#n8@9gD4O$ox1lgY)JqY=p-0%rF+NA*!1QsMOB^#`TtJMTJO7 z@yIaZ1*9YuMj@OLaTbI$r;`Zz!`@48_w$gF>Dr6c8XFf^2HN0;_?9U<^jSemvMs5? z-dyx2c6NXsIq`=#nokSc>J%&l8t{hg;J8^1!baK>nW8dQH9`V%)T$FKGKK^kuN0=Df&-G5 z9 z{#yqahx!S>;KgN(OF8HjW+t@`ay1A@^FmsBfR*2 zui_#K!p-q+)#g?e`O-HzyuTFSr_sTjdJ4}+{P9{uxMK+8`A zWTFx)dmjxmHhYXZ+Z7HFU8F61H@Fs}tv-~|2x}ouE)i}NjLW$JU?^g^f|OS`rovunW>?L){fDqkB>YI@PF(UBGbLYCxh6xSWuX)V%kaS=OsHed zgp#Lqhr1H0UTDelV;&Waz*=LD6fP}wWsH6E)d#i}ocV|s4JJwl_^~!AX~*DgjXV@f zw|>#WmyU#8R#HYxMoOkD8c9;#W1iV!)lsIb*m!Ev@*f|3dly(8L6)r@-gTV05^D6J z6JjZlijTz=%PDd)O z*AOOi&t>Tg9;#*tuisnh({0OGYDr5CS9kvFnUa(x-761=i8WJNB*=>U#9k%X8b~5oezN4 zUyEp!?kqzhqZtQ0twz_~WOH<2I|pe)qiD5Ndv*3O(XPLKaE9!X>fBqWt7KO@fj|CB zU%iuX`6J}Jp`Yl~Zd-~e6)jivVg2r_AC05l1Au;m2{6>fZbX6e6=lJck%T2t1y;IboTb8j&FjdOX6E0 z93h>4bA31g6?HfX6H(ASZxAzfGoHZ7oIbJ<&X%h}s)KS3b8u_J{AuDal|?~Zi#RQk zJf{nuHB7~70eki)^Wr0?IHr_n+z{PpJnUrQZo77e-Gr@=FqUop8>h*Orom#5EtZOr z6w(LD(!$^SwrraWZq&@1gg@BvBd9vAxNo#q&77L`CYDoJ@~wMvxu|MQcP{cK?z+tx zXDRC^24dp6X42doc)=erb&nhd&P&Fx5F~!gpi-0=u_Sf3D_VNwQ+?&zC!20QXZ1Kv zl!K&F;^&iHS`@v}StGzwSJLeBRe*T^?S{L{s{zT zwiu!OghwT77OnBIw#ERy)nxm?tPPKUb-b~#sKiOss*kzMjr8+j1ul;oE?qlbgcf#p zIz)U~mQa5%^NPU2zTMP#U?lkIQi&L(ja(*4iWl{MO^%3M%2h`)j1PBi zyGL;cv#z)Lv7CI2y7shPql%MkE)Cs6scD76W(YZ0?lotkmBNOFVZrEa5{<#2ozH?& ziOKZDa#i;(d)^bII;kqJNS3e^u<4_nPH#t{WK1c!rRy`&f8%J5r$^G0+8+JXls6o)104P{lDdjz z=oc)~K5jH{cVkr6Xlz==d#N}vdNEr&MOWPKW&YTAOP2A@ny7ib9z9#yN9*G?g;V2( z$t2s|nO4^tMs@N&HgF4KZYFj*TNi~7iae>nn9;AMxYWU+bRz9(y$=7zJ3HJdS`?-L zlAw=Q8_WvLD=tdKe7#P*+!RYJ0;PCjAFxjLm{-!j3VJtKLP5j8=y+~%F&&V}Vn!-*RxlB0I~ z9qSyAdKxzk%y_tb_@A#e#55(e#K_lsXH=OY*K$f7QIk41v^xCQ$Tn*&Mz^z${dxit z^-2l$no5+_Q`$FRnM5L^jKIO0Tz= zOKLTqtt>4UBIVI;Glq&?e0+NzxdRmz#zOCqOsuJLu2N|Eh>H8=!Xd>w+O?NXM08~) z*>k6rHs9VF{UUwZ=k2oOTL;>%C^Fp!uUEdzlmw-)o%79=)G-zD4grqNi7sJn;z!K} z6HpxDW^CyaCYQM1_gFu9Z0a#KpHX1F)9x_$s_LCy69+$7$iR%+$Ar3f! zA*7F%CUV_(o>1xPtX+;f5qH;Z&nVU@yf0ue-;sXgS6hw* zD&YCrK64~p$t_U*`j%$q zc<8;Ld|sdS%<^}&8GS4X@qV?ZUCvyoy!MdesC52jD{|tjvQoanIfi*=s#hb}`}hq9+eL;uacuj@R%pmN%;Z_B>asS4|w7YgFnd$S13~+-=S@ z6T-R7w9gkk`IdO^X-q9#+d7*y_4XLiqx(%?5)_p)RZkV`Go5W3?^vSGrXrZi(N|pJ zT9{ydeRk%fI8-m4PAgHY?9nU-isp;-)K^~=D8o=WXHCDHo%6nA@lvr1fBfmkPtf>x z>WeBKDh01`(n>$aoDRR&)`W3eC31TykoLVe4ok1cKw^vAlgNe^=Xr57`Qr&w=lGRX z?Ug>8p1(63IvJl{I{v2hlFWKuoBFNgr6$d#Qwg68B^5_c-imaKJo$Ob4##8QiP(dJ zr2*wNR(`_SD=rInhddjhTBs#od6Dj-GPmBr9i0eIdZ{rwyyp6O#AJY^#1d7&jwG*j z$#*D~*|alemAtb<0!dlOne+u}4{cia=?ewqu606`*s5u7sxUo6}x*%t%18&9xQHE{ zda145_?%deQ9XTIGw($-vU$c{5BFmwDDfKVb4{$rwhOTMz=4-9GD6?T#VdZX`Wa6} zQ`q^`5e2*Fcg-R-+}g(;@|XDwPeiSiFzJE@W{}cHcJG;9`xTBnkGb28JG}&KhF}DZU z9tz_a;_g5wlHWfPL}r+r>dR0zk30`uzfGuhHoBBASFMSkhgVznA>NHsJC-{!pAw={ zC(W=t@N{RBf*o{`RC^fNlc+y^zV|A#6!mVc^o+#Ar{4Lzs5h%$Tir-hd@+qx-AjM< z(SqYCx%(2Iak(slU!P~TuNADhjw_ICPi(v~ciGk+v#KJAPOr;(i&%uQh{#J~;kB0A zk>0TfLfLKI60}i%H7duxUh`+^2@X6zgf>0 zDW`(1Nd`6c11Vyral1Yy_Q&a$2>AyR`PNBO^tLas+BmK+UVT5*w>3MNTqx2c?2tF; z7~0s2cGZgCZ;Vv4Fbaz~=$R3UPl;5R)J40a7|`Pn(cBjLsd1H{=-A|TB;-s~4}zgS z0$r09@$9s-vv{a}5MiIKui5i9?Jk1e|t#aRWVO@|; zFr=(}O?fB5V2lkbV0>|{CqR2p`ovmZ24%=#pHBKamys?AcgEj#Khh$ydGLB)>T%og%S zRy(Z@L{U+^;)6)2jXjo0F_tWGK%MK_O)Bv=D^gN{^MRc!8;_^bO;L!4qjFa<^3(m9 zkLP_@S{?Tk^=_MZNPWSKQY>5H^Aw&O`+eRNL-xF2QsL1st%V0KGTSug2a?{<)OJK% znW`L5_{FSLU zbUspVD$NP7d^|mlz3Uw~nv>gpOV!KD@D#;2eAdLDjnJD&!(P19bCld2Rop0(D6MPsz2XP4DCnTi>-#-5 zr1-oqLNaku%-gKV&Z9H1o-}ghM=L>je*6PfsOUHkri`*r;}%uVLo7@)4QzWhQle)m zx+!DV-tq=Vye6&jZxzz`$eRC8L7_LQw3kFr6#Shmz(YKuqoR`o;uaReJS$??8h4jkE-vFZVG9epgv+ko`AJaY1a4$Z~jp^0> zV0m;t1D(WrN;CYV6-T^!6z^%@D?FXLXcfh0)btY~=Iwf_33|hb=w^c_kC<3vo}^$t zy}G4vW*qB!hg=J)8v{QHZ&Hq}EpJiJoaSI>lVqiJ)5%6}%z(v(z*VY(UbjyPMT$AO z>GTY;Cb(wO)j3i-9_(vluM*ZJpD10|!+)*hu8!k4j((~xD&y@!Spe2f4U1Mk?-y^o zwxZ4Ur}Rm*M_bDf>eP_mOnDDN^dk7Ts z7=&JxURdFMRXSMqp?;l|CvBLbI4w$*_r~H1Va;?Z8QtfZv+*hz<;zWsWC^z% zv?g3CXcV{sUF?@fv+2fjk1HA(vUJ{dM}rb6RJ!EX6`$)AO1jxkUb`MhSb*Cilp==0 zhJ$RHWHHBKCO&x1D#-Wlx!8q^XTb+Z*-6|dgg?LBa8)5kPNg=}mhzu|MIgm(!l1+R z^`Y?_LHSZ+Va}Xc)U|0#LYnQJ#8^9)byH?)R;iJ6qI7{PnN}ItSnDsA29zR${Fq8! z6|+_! z!XR4v;(&gZf43!RoY1LK8sj(HWAIu%sGJkUFbMMJg)vk5PmS^<5!%i;L^c615t1G#8s&PoWwdDISf-q)TSg=Hrp51;daOrf+)j7Y)*$!b{ z1${-9omK1Oee5`rXU>FXB;PWm!s$9uw)6@Q*M_RI?nQ!b!#m~kD7=J=L%F3-Jdcr~ z!^AvKkNeG*NZyS+o$BAAf4_ChBJg-xmMa$tVZiMHN6M*>x+@_$96wfDYjC_B3Kc~R=BrH0mJ%8z}O3(IFFgcRe`zVy#d*R&y# zA!QY7A-hpPjjkMJrL!|Ee-fG4E%G%gX#DtkvZPOvi`98qI#!VLT#Kn*iP34%+FlD_QgfgN^2D9sJzS#UpfJq;FA0@ z|GV|$=r^m*Q6`%8mwtv&tSA@}M>IO}cXY-S(=AR9`M{kL+cYf!)B>kugvc@uXy?;uWsLj zd=c{}cW)~GQ_0WK&o_9(&~hi7LgO~@Fp9ceUNa12G&$Wv(h$?7+G(Nlyx1HXdj^G` z!KtfKE;Zh6(grtLH1Iglg%8oh$(ELJxfgIR`Za#M6%qH44NKT5#6DVAM1+*fen8Nx z-)V3vODFucmikh1$-UZ@)RbHFJ6?DIps@rp;wdz*e8)Y`qF;S`o(fuWdghP^bk3=H@qL=#E1BytpX5E1Oc2`Zz-}QdDwVWE+MH*%wwtv(c~gC5gENp*$U{jXu|yYa&VBOcZSlT_?aCWre($xWgeQMmC1ZtR z(-NP0J5^?h|0xD}35G6B%K3Oj{pVZ9Xpb=Q)IY}3(W$giLR}YIa1Y*kabE_= zM1J+Qt3WEgCOfLfmooLE&x6impa}U3ziAQO{FJ5<+%wtXX=Hdz^OA9`v%U?@w76{N z^aHN13edm_d!dl>gywZkaPp4S4i02n5ql@3$&}e(gNE$udseD|0v*b*33Au;C%Idy z^%n2_s%f8}TNIng&aT-s@G0n<8kcl$zf^ao(_uNwCOGbbwtiJjk>kmcKoZW+%CEys zGND9k%jPrGCDaT!Qn}8OynV6kW-3DYDniq(v~nm$Gj}rep3QNl9liVd0>$m9$WN zv86}y=;jG%XJMFN+)sGR!}vdhk}f5^PG@PV85ri26^b)d1WiGzmj z1>yjGwZS5`Rg^ERw$Azqc!KpbjXe_;*4pdV&0p@&uc9tc(=ZF>*uP{r{gu({eSici zL)?~Me`k{P8)o;)2w_@?I4GJV738o%eKH85_U3t^X_twY!n#_2xAOw9*L8OmF zWLRf)TX>L9=wRK%?-NiYq*J`s$RdGNbJF3MC-=~1Sr_pQmFOtLdr@{9TwAx4V-w`i z4HG^*N`U0hR}!cCW7kQG*m0v#*hhKOtZ>{~7dT_^)>q~GSuT`LzEq+nGWB10F`F#IXO(%`7tQgjmg{SEq z{d!?_Ce2zQy^F83nGLgVwGS=ydNSmey-d}~qeCZqB=q9TgFtAXKGC?h&Lws2c8W*6 zOjRDS#kZVi)w(<@Viu40URJiFVTgQD!xciIA0nL^jon?)SIm@NTB&D7led^(I&@NP z^y%RG2jyC`SvF~6vFm9Lln>ciQ@QJP6$Weqct~cIGbP`kh>#b>#MnJeg0Kw@LX5uR zQX^$J2_}eF9(Vg_+{jQSNoEserxW+ys8~*b5&cATLE_bc<)~D3>XS)6g}1zJK8H>n zsn&}m8F9|EtYboF=~$7Wd;ZoomR|A&Q;?09+y|dgV~DiRD2sXx=_HfL3I15uN3#;O z<%)f2@eBP~?R}^5v4b(C!z5=XL_c(`eKZ@+7F3sn!J~ZFF;PsJp8Jm z!Xe6GMzWfb#=Bo~oj8-gaQ#dH_vAI*;SkqpOPcZJcT4;=gl;^(OEGRQ=v)Qnp@i}$ z3(n^+#oE`W?lY4| zgumoYQ{1z8F{z4dGAi0S^`2_txF~H&X^W0kMx(ZnC>wfT*s-OFf%({6FE`OLsST>) zN)wE-m17#Ydh^zW8z`ylITzkZn8ir(FDDzAoaCB}vRQkZJ6vk0>T)9`#Fs#pOkzfQ zF%Bk}=K3J0KTgnoWHK3R7|r|KK!E5w4V12hqPw$4D`Zwr;yz9C=W~)|OU@+bOc}{? z?Wd3&7l=Kgd8;On@*a)8ywt`1FJrl`O7d+J&DD`326A#ttYu=0)500+z2J|*7Cl99V z*2pbkj*CJ$iEo<;qzd`MVJ>l#-UR$ty)HC3HR^>9c$s}x3$noSpy?D^a#Z^2A~@z1 z%yCk0@s&KjlKVKSHClVXwUGYol{#mq*I`829n<1+!_Ci|vMj`)(Ywo6MDWWV%11F32{GxF-|#Fj@_Mp`FR%GJU5&7+S=^>TUtnI7`0kmFyg1|< zu}2ElYD$$%rUbTxcRf2IgvpOSH8jICuOrg-RO1K|S`AEtikykh6DcFFk)9=c9o3P% zQrvU9JmbxR--XNPuXa+UXQdQL$wf43+c@DDiPr1NQL}mG-QG?{|D9j}7iPWY(Lh))Pr+6_xf2=o%ZI>a#m&ZVEt*lyZvB;ddUeIQ>Ej9A& zY-vGZW!90J$$<+mS3K_@$+9~;e}qmlLZmR&bWVAZ%b?Kysde^r5iUc z2?|I=B4Hv;`?6{~H@Jk_fxp7Q4gY!R?gfLN*0=j(Q$u?Th@Cyu76ShV7la*RY;6G! zPdx{LSlC)PLm=P>>Hn6y0OU$5@ygsefrNy^i~LW%^QYXRKg<0lejlmgf+w!6q9Gxz ze*Y}%r_^AO#O0J3#xR{49MV|Byd&|JVCpA!F-!e z|4}s5(b3M)X^&L689s=&2MhvHtw1u{u1N5N`SR2MQL43_nHkg(G}zh2evfQ;ix)ZP zY$$=Oa*Lp`bKu(qM4{Dx77CZR*9vf< zU#V}q!PD#TFX<4ium(*12e*Nk`&FR9Wy7@wF8k-Y^!*8cz-cM&G5Dy%8M<4ZV6R7>7s?~O2HrRejuAmr zPzKoY0LI%#L3qhd`2XG~s`&3Jo9BQoRu9GqQ3M68L4}b24Yyxxz!AIt<3-?kfYN>#&fJ#1Nny zAX*Nu9~^38;RrQ$hPXId?*m+NCmVSTT(^vggd~ChjFtq(-f;z^(<_3#`iQC?4)VPte~0d4y24cvA2eV( z4PZL>S?jwO%$FEUItPgKANoK|z#{3_pvhWCI|HB-2hi!_E(JVcz7G0_1HoNn4ZZ{V z4Qx2PcfA~h-W3pf0thfRlf%P)trT4J?yxS7z!5V)5NG!sEGLMw-L5{r4GqYf!9;1` zFMHrG5DPypm~ZO;LNtL|L&4*Um=BZ@@cEAa1K!^5XF&Z{eK>O0<%nbFO}7K`Z7gg}K&7VNEx^px zhETeImVLm;h~0AFu$0}o-0+`M8-6#F!w*i~y^G9dWC#x->g+I^&EOvifFyHk<0N{rD zcIwVvS4?DOy>SPz3tzDzDj*ela0R~0-){~kD;1l41^{xPbAUDAj|=8|G~)1p9}A29 zP;lA1&ba&o1a}5`)B#b}R{!31LF^43oh^(l><$00m_H+VK@A4HqymeUl~8UeQk0-C(+{}T-{F?2TEt^Toha7}BXN(=$;Y;cPsG=i)A?;2rY>k1V9^`sYR zee~XaK&k{c;!=dR;_rx#cGmDxRC`sM6L?__FUFthJ)BA}xD$v8qmrqXN4f6_8(oADp>+!F-de4~6=^B;Ids zay8a`9s>lw0k`Nb06by7Bz1qqfFPC%+pCkU>nS&NFjiR;?$rse{!qN#q8aU~r zzO)}6V((~S=Ljme?E}(RK&3SYqdOWHbk76W?gjI0=r|l`_r#sOK7WtHBn(f>;{Io; zb+h}x1gNQLjEJKKFMWpS*^(FYy) zo$OnFepf!sSA6K8!hexU?k_t*FAmy03c5RDSI7TwV9{Wq@MG7xPxJ4iMvAKeH*oxC zcJul-uC;`hmB+$|Jq~Mii{|@ronQZ6Sn0Ozs+Xvup{#}27C(KuN?!dU8 z?-U^4>q_m7U>x~Ma(KNeFMvUOvEcdXZ!o)q7lf0YV;@iPuy=Jg0Z%yqPhCXNO8Ltn zasMRL{+Y{uwIVr3RHo|=bejjdAtwAiR}Tr>O}+feiZfQaUVsDxB*bNh;`(2b{$NNd zlP6+ApvNXreycOKYfG3f+t%L^_nSj281oEVfL=}i3Bs2s$Ol|={42rot03G;XjbS0 z(^@x}I)!&N`6t#x(Ek<#cHjGEbcQF%MlTeW{DpH*Z=R|1{yg)BnyMKPdM5E3aK^?lWBS z^bahKJ`H<|9z8aN`PtRBlF(W#5U7`8Q)*z?W4j#%XK+QU@`?T2qUh? zBDfALe!pLgz<sqsfo-A4f%YK)QdfDrpsBEJZzfaAuDp&)SK`+meB=e+1)S>Sgd zu7(!YhDH|F`|m3jMVi7Bfnvy*dtoQV4iEc7S20VreD4Odf^TIJ*MXFhhle@Yf$Y?N zn=;GobMMoEPBuU%X@J_jV7}9b!yx>2;7@Mj54?Q~KJFy_XWaQJa~S1zGh%<@iCYdJ zr2rlW&=PSfe1G|Gcus!;`b;A=!_CSIfRej51y7i7x8h-d|9+wSCuSsRl};vLY5=Aj z0&_z7FwEUG?~k{ge*&K%Qq702x9rAJJq!(G)c=GE|&7JCQ+X zYyw@l5iA&Ieo*-~&~I;Gev#LZs^*oj1=HtKA|xbs1jHw+gCm@r49)gS_7=-0>pTEb zUxFKP>-x<8kkbE7C=JOL>z#B5xg!(mCk-Hq?9{=I86n6H}a--CXeX5L$j z`zMm$?V!k?FQb38c-~tj`6mV4<1Z+G=sJ5#x&EZJcpa4X@A{SdtPJ-S#r%nwy8bta zU%x!rTOIEwN#^E3NxRe2K8ozE&-GJ0L(oCRf1e$GRO{NimDyX6=O-g3^q`FWe<-lG z{K!wqXyFH!yl)a@@4@pwMVm$)SoD5Larh}Gdk?GrDLm}q58=N#U1j&^>VI1rE_d%i zGC$?YoxKMz zfc*a77$j@3GJf;pQ(Pn#4d_WR?Hu z$RL}N*;!%sYtj*|plX112m(Q}>&NcbHw0=mv)>Ij;+l~gB3p-2kp#Y|o>QV+T8m{mkO=-FhzKERKqxPb~1ojJMmfPmVq#blKua3vVnV*HFm4{oAgqblX2 zuy&c%IlWt1cS*!0vJvrFOSg=QvzvKkDFx!km+%Rk zk8l6W^>=yPv=e|jMC1l0clrq6u}zz0$|!qTWFl*aub8oLA^ef3)Kh1@*q^Z=f>g>7 zU7XdP<)}2VGuWTn2cVKYfwWS#9}*d*hu|RF)+yIod3|_ZF^{^#-j6bVap-u{p)63}Yild1h%MS+^9w-sZLJO8PM0_N=}b^cOnRImnor!(l# z85yARH<;?(R3+Lr$f;`zBC8{__QgWGwYZaRG|JK z<+T*XD)Y{I>%*0X8$;8>k{-3Qj2|98?^eCZsf2lp2 z`jPfGX$C+LPKmanB^%v^s8C1*r8a{W{Ok()`EOu(y5~OJ<*G_gfb3_c8VyOQK z+Z73$3tK}VOkM(#g3`%~t(p0e5}6bia#IgnH~j0GON}>-J9uf1(AA`_IRDu=>N>z# zsU*#3VIxcFR*-kiqDWzNaju2>J=VZs|NUW7NvQY3CVx@8t-ps@6V`D}} zG38#{*&zxZ;$s9e$c~N<3#iT!Q|h;t5FI0743^?Z(-6aUs;{eewfjV5Tb^93oba&b z*;i!s(eYs!Lo!#ELZie&yle%(YSXSNU*0sz2}2mk={e{izBfswh9!9VxT zXzJN5iz4{Vm96WlY>34z>6k+ZcZMwnDhohcE~P0NXFQR$Z*Qn=t)Uf&$3NFe77!qm zBgt=uwaT5y6^4?4>lu8@d?Io-T{W$}-hM#LuOf1KneuRPJ!SEAjo!e25fHh$&t7%@ zL{sB^+nbtF-v1qbAinewMRJ^L!oO_}+BZU}lds(OMh7e8m2s+f18o>YvTex_K4O3Xgx^^7N8{2ZHCkvHj{nhv&w5bXcHe8p1S_Lu?A)x-t>6pyZvmcX|E4h(xFZC$iS6@7B`>MJaa+u5yHk{fxNX)V_Z-+BcbAW~rLeVqww+39`eYIxn~ zdSj2s9ysph;uM-(1|xHh4>68zg(TYm&U`+@XH)|z8}P?bP$aNn)ZF=c{C3=Zg(}mu z!Av1==OkX^NFTF7#$Rmh?#%~&IcoM@Ha%7aGbFA#F#-D6dxNtBkt~ki;?ax#Ll5WO z&=R1Y|Jd`(hbaoj7BMVK(}>nMqXXfW~ zNU;!tx)Fy`wGp&<5lL5#;|~6rKd5HVWo^=dR6y0kajEq%SzzS_X9`u(1B<90_;>5k zRO6tW$ZDuK0=*XKD(e?;OPleqjWHqOygdME=3}8PDG$E`EaP0{*YGZfyZ}`y`YJ`3 ze8(6?SmM6W1~eD>*(NyL^`2WL%-Q^n!G{vaF!Q)-E$DPL^Kc)utKlQiv=3M0nxjhl z&z*=MWm+tIcH)S3a2ENsz*i1EU}%%|V7uH2y&f_lyXb2qor;tUuIX2GO_lqAi+($=>;0w=keoH~5!YOWD0}(= zIMYQUxateO1cL+8}5hKU~1lN5S?JJe>EA-L0R19d)>Jjt<)>|y6VinL*pwFT( zbhw`#~A@G_L6EbpdFt7?K|fgc}?&InS5A1rc{xG8|!j&60Q?-Wo4ym)Z*Qf(>3 zqsBjp46uP)jO#%`#{3RmP*3P*sWZ7so@zejwMgin3(lg;qDnrbtIZdGfG3$q1TFA3 z(2zRJBl1A`^$)7*JE059c5-AAN2N@#xMi0%L{EDlj`l~EN}To0E}e?9(P8PwU|n;* z$9)5Pj%nRHhiV6wY})$*K#$$H`_9+rh>Gus(m+#5|VeOc- z1@o@4zqr*d;12qN9_qNi4d1FUl&V;7Kk7+eZy8)$9} zlL@WKBp(=Z#j^0OFIy)CV=gVp@z@*pP_xN?5UVs@aWxx#`Mh1ihb}t*YK7SG$WvGE zmZB;r_0avXUIUd94eV78#1U2bcDjXVnLAAQXfwFy6jC1May$%Ple_DMOM7k0U)&%pO)cHsInHB z=fYzxALIXe5DT^$G||kA*-o>aoXm@GeXffKQj5>e1Y>u%1mh5jaG?EVZRKif=jD2L zjU9CZ3|+H2cs*cRwel%W=>2BHm?_-C1?)JR($Q;zK{Y!GwFm9|g!e`<@CNzI8j5Ss zKz+E#;VsuH`_L0XH)bQq=3}7cR+ zQn6f$BT`?w$34|Rb>3-S;`57)9#kAZ`54rT(VkyGlzoc6o359hvlN2ths|2U^8k62 zYb@5kpcme5)60Mzaevmc7X>*rt=&pXOr7H^a`8;9A}dBvnUm{4hCh+2 zmZ`9E;_;UcfGwGQhLb7QH)kVVa3guO!h2=iD4xgIkD5W~5nnuWV4msZZsH}w@4uCQ z|H)AK*3sd%5C8yTYyklNr4|3b%F)rp!NtVMS$ekY!Ze(Ff-)iVY8?qA1dfTIQd^JMP>If5>bTy)Xd^g9cVz!d~+ob3%pOssX~z{ zlyCId-}0vhueN^^AH_q_kc6nEjf<&^OOK1mYxCBHYgV&t%We_Ytqu!S7E)xPOzXO8hd;cgO^ZBUZyT1%>o50~C5%|}+-*5%ArbUXHbU<%!odN>S6AdIT zF`=WAf`U|4ZBWUaWhe+PWPc|p4oxYY9he#%3R?k4^V8ntwC;4wuaVWo4ROlxjP?uF{{3>) zpd;LDp^C=3=X7YO49|pS2u&oBG^Y}U6yqG>L{<_~*U@<`<-P+dJ-|%ntzW@^iu*5} zzz={;hOD|~<|a^Q9i(gx`Iz-bcoLoo$qsCNSIIe1$N4b93%m z+pJ={klhEqMeY68dJf(N<|?@Q?rz)ZIm}+#ICdvs1Dl$gQF`IX52`MHp1bTZazl&k z&!zDNk05+=gMrC$g2|V9E_k0kkaA`5<@y}lA)NgnbqtP)G1vm^ybjKh0$}|h!tS?7 zxE%+HG2Hh_8uXJuxb^4f4?Nf<2>1e3M?-^N_3JZWK)4Bz?4ii-_vZmE|JB_6{yJm# zAbm!0X>hLW!3=(+0L;cPJMRzXGmyVgg7-Mqy`zQ&;kO(nNyTs06^nmGBuoam6 zWq|wvdu8yYaSav_GD7Ji`k%>Q{mt+Zm0b8c&Z!y9=Zu94@RqZms`%WOhz4w7$g?x9sKUZ&?^zM`~ zZj_gg8hbZ8cGs+4GqLbKkRz>YaND{_fqb)evrqj}%AvyEV)q^`8~eK3}rM$|Ig zd7)cZE?y>(UA$_8AiT=plp#dcON_S0ic06MQ%d75+vj4hU5} z7s%AC%7h2di-g4*M8{UD)6%F!9ANk1mjL(`pH{-`fRI+10n6eL;3prL=HcL!F8x@P zZW{b|U+K%l(n`5#f}l;U2rC5chLmct3kXF7c`BwZWXzHwWFRB!xkbIO`F0sI$h)2x+>2_@4pX zKWninj?*IQC5iywVqjS-#6;_`vr3{R00YO3A2vwud=8DZy;K0YrvoL@kMjDLF4=+O zm0#%lbZuQ#A9_ZTVg`$e|2`YU&`>AMBKv^h*U5X!J0tv1){Pn%&*iw6S$6N%Suloi zk35g2lSM;8l7g1fp!+f`A|h*P^IO6(I^d#9+q+fmZRqGqFgiwt6%{32f&~ur9=J23 zJO1`Z@4CF8HI{Gi8XoSao#3NAZigceNCm|~+D!1?ryXXK;?#0*#j;j2xqC~mXY}w! zjfu^#{oP;txa${P-CJ*u-csA^miAJ0>$4slZMWK|qZxf5UOvg;kqIF_xaV`y#r1N=*vI&U z4}M4(V+gWxiw+!^-HtEbuu1@nn-2bzhDf3-jherm{?^~hyk>*2(DeYPI zl&a6Fse^uc=~ibC3ZkuDz>KBx6!z2o!2supE<<41FvGuD@ID@Z z**fmbE8Bt-^N`=Z<@{sX>%>S7r}ActSKYX^rY_QXqp&P}lq0N7cZ%zb1UCVw!ZtGs z_YULrK+jvqBkY##^8@Js@D~RPoJJTlWlv1K-jMec=5Lnz9@VoP5jQ7%svtn+Ys7l6 z^{T&NqykBD2v5(3>#l-9y+HH8dr1|Htopg;kfS4HrdtzkJ_Q47(%@dvOHPz8dcMBh zk5KIxVIG1#`3E8%Nh$a|Ts$%O9s)cTF@Nl9DLl3Y9!e3WG46)hV>(Pg@digdlG~MS z-PWGSE{9wm_2G2nb`3=b*B?3PwL0y70#w{^r)o1;m~ug5?&3Kvr1&s+lLfj99BgWu zn-$VT6tRP`(juR(EicL!6#i&lThL>;u`sq-u<^@J%KLQ>k2W+7*g4 zSK;~GC&5`Q;_AMa)2u!ZBOypGU9EiAah5A0Fbme(K4aR(cK;*H7MVhjszPxJm3@lI z@IDtW0i!LaE!vDcezNd9ks8{yJ)|3nosk&IZ;|Z}k0mQMzK2cScya&zCD$c*tU{Oy z!0U}|I0R?iHaTtmv+m5ScGC{`ni;0)i~?mYMjszZvk6CA1%q_v^zXzX3QP{!v)Tjf zOVNXIj9A2|*|>Sb#KO()Xz2&Bx|cFe#^Jz71B4w+Cn5&DwWGQgWpvMSHYu4>Hqi{! z8V!@X&d;dbnej6hBdb^b)30T5+g=I}JdtOr$Ngk0&?ozYcS)EFDcW;Py~xF8naf)h zoOw_26dJKZ=0f2=dQ_1CjVA;fnV$9F?ab*ET^#f){uPk`M(`9Dkm2kku%e*~g$wBh zzBs6&;hDjRmI8|2#A46~iZ=w!+zcsDvFOM$QsxOw=%CXCu#~Iif&_|gZ>KKR3Lt|> zBGGkpGf1M*AF*7d!h)gbe$x27rXcAl;xkEejuI;uZ|E!~l7^142R-Q~RLp2kT(?D^ z=HZ3kqVuS-t*KN}DlcP)$WoB161+uJRqWphwXG!Z_Twe?&X*>nUgp*Pt)11B+6^Gn zk<@D1m8PdI4acMzo~Bmv+y$mx#|i_K@#!gnN~*FdbXF)PN~FVF=&F<>ZBL@Q9C=g) zTT$bc7gJoQ_mnylj2+kv#CV6eD5tRs?%rs2Sny-h%t;pl-eV%3(}+aOA0qOo;};AJ zquslnD_>$(I*BjR5oa11G(I)8Kw!w^+`btCp;A`v1%d%XxS+jn#_=Uz02bk_UQpVv@a8@ubS9r1C*!&V3WfVx0;7P=fPJA@&WUt2e8m(C7tdapgpwWW>kt&A zL^ho4Nex1b{>;RT9&VYmSp=ut=C_$rD?~INmrz7%! z%)ua|lnsv@jmudeP~d(^M8PeVdkOg3WU#5=jI4Mq!u0KEQxJQ(&hqVm%zLfULxuvA zwIH&Fe^eKUScSSkgM5$>$!x$F|CE)}8eky;&LK9rnauUezAH(#Ac}~YbKowfjp=g> ztk}adw-#QWvFLbl06@vwx4lWAkE(#70PYR_T#}+k>(DmI4u_+ffCM0EXWbo7=ne1% z{_$d;Srfje&h#GEg`D(=08y(s7RG;fypgw5ux4uz0EzoDDs;yO$aO5|y9o0aKY+_8 zfc()|=h>Q$4qTqQgV3$g^Z8pdl?1bzk-43ix~0dD>fT$=?JUwc2x$ocGaR*cIzCSQ@>E2yX3q@W zt^_}5_qr9uOH6NYe!sqEv4{g@v4~PF2a+e?hLu8&y5PxGr0aP+q<6qnRy*2+YV-}c z2#Gt7?D=AIPrk^xO+lCl-Kkx+Y(>Nul*Peug>a)O=!TddLrtcin=@0=rPs2p& zEESsM4+1vPXrvHf#0Y(u%kA(bx+1SOXb4`aR$gCZ-&z4Nogybdme@FD;o)mPU&a+k|ME zv8ThQXCk|=lGb)8Q@NfwS6xt&Mq^sflkINFqZzwBZYLM+M}}7+>U+oCk$WtAUk9np zy4mUovp!~0xfWrUZomXpEIt}-j5-j{!yq;9wi)FYJjm6othL%+A0H>4P2y<3@2FYB z!HkmUArj0*Z2fD6VE&f09R-U)@#=u`q>&Fl>d2*c8F}w)w9J?xKg(#zRE~5c=ao~6 zLYI#e)Wa;1C!qHM)6GhUP>~gRMeNe4Q0Gr5HREz3yEosM7nDu;F3nCy(l54%k8r{B z&cqIflgOsXMVULlp(ou{j>ibkQ0eV&^afPkZc)OA8Q39I{$&JEmrJUoC#A;-*L2(n z1UIbj7Qyp1dq}9la9L2Q%qnbbY>9Mqd4?P}%9IDvR@8BNbOH4ec1N>Tf25aM$<@Db zP!l$vsNkR`tB`(Z#3AYUmZY zbzF=>QO~#*)kvd(%jr!$`x&z6JuMo;f8=iuQM20Ob&W}G+r)TXsDJ}|`Al_b-)-3s zeJa?~kSB5L#khy*tz@Pe!>7X_<=Ig@;3JPFF|rWu5q0enh%f-jc;Vx)qwj4u9eQ7u<3YK%?nAf4xR7%Om2; zmDH7$kHJ?R*pErZ;LywV-~987w-%-uo%~IuN(i@BM)EMKgp`*$H9L$Da+C+{NAc1~ zQ|35b!A;4qdS=gk-LldyVGXR7uw_b0wl1pbg(~0)BNZHD5qaL_#-4%xOYOUVYKzOW zNyPpG8==_%0Vw|OYX5KT|MhilboA`7#S;DA$}sK;^I<6(k%`;2_U+rE^xg1pRaAwuQb|9kJD*6&(xsgBvOtKKE-Dew6JtX-2i7rMmU zJ`JwJR)L4?^vbb*o4ey0pR{(;R^7De^?>o&X_zjNX4bvXl)rBRFMX@DwGjXIns99G z#2VGqYS-$}E90xahMusW`bha^>q%-3gqR;d>kiOw9R6&a`iw6*GLi_(`JDJy<|s4L_P4e3HtrVivhQ@R1YDepDWC>h!z>RS+^~ebEbaqtapqr?L_?>AGr9AwZ}8*2T89QB7@2f99Cd+o-8a z(;*V0`f91HdP#Mu^Xt>Z{I+ps^km`$$i*2NhmT(H+8;A|_h80~&Kqn?TIeNoYt}_H zS_@jZbm@kZ2x_)@#i?32VnoC#2jE~CqHZ2t&FCZ-SB@TC(8{@8Jaks8qRsIAdlsy z=vea1+@4okV*v(kJ7B;7W{wk0KFkkaKBUBAa!}NfO|(TE`B-<)wkO8&G%yzi`n>&290a&76J-YmJ>(GEj8>zNNDXPG z?F)51TVU-rP3h#d=sjyJ0701M008a!jeQK$v2!=g9aBGO<5kOt2>tj)CNA2bfD})7 zElX#vm|i`*AoLboqoTF8O92n^lX}2WgSI=}-$siB^$+3a>b*DGF&6D7Lj5+^wjlR0 zAAsTeSMAqgW`Z`1fq_{vWJL|(7id|NXEps@w{dCx82}FyL^DD-FN)OrJ?!=mynu=K zh-zyLFhYnhCk^nW>($PkL=_Zbyj-SV{mt5FqAPW9nM*KO+aR4d4P>@ZcHqltAOJw zK=BMYDgL^{?r?;C{ofMrUM91l_h0(=UrJQLLr&5a*XrB>ju~p)cn0!R(!3Ep2PMrE zG7(w2cPAOr)4=&pc>Gt$>0!B zimmnCY9&Oj1L^&6daKHM!@BQb9flW$w!f@|_|tfx%!hh;52rG?u0tj6JhM;$R?1%ZoQV= zpIjk}IV&u+k@9d71O_|0;hT>|OGPM%Dd6=m_^H$eLRR|oc#q4Mo#{J`tc%Q`sarY_ z;YtciBmtPN!?!Y}DRvTa7UG?|&P=T9v3O}lKi+OgU>oU)t;ySSnxz>nQ=QLqvj19# zezI=r8HTXO(7%SPNb`I#W!d`4qiYe|JMU6FYb0F3IDC7=@trzoz#=`5d?Y`HWvs%} zpb=jHrcP2YkM2@+Sq(!T5T?!rg}dCOV_v4$M0_Sj1Yrv_Y{N|>kDV6mRX^ziDiC3d zZw@!FORzU$HS)S3^08R!qJ3I*F96GrSn73S0k$3QEX?9Lssv4bgD^!S8Qdt-oM6F> zAs~AUPkC=}!XRJ@!4Qps+p!T1orLtx# z(g$+r@F)X2PjF}J26p$s@1g6lkC{72^PUN_Od@k8UIN8eOngQ$dytyjql+WJ z&M7f)7_z=6*APUYo}}(Idtm3uhExpV&Ijp%WWHe|!^g@eB?-VZ-d$B&^QQF){q@T` zUp0#j*`_;o`s@3la?cn?<55`+0X;FhKs2Dld>9*}go1o=O8Ml~Rq_P`&@XVE;T>zN z)KlOk8-T<#+>dV8F4Fyn^E>ewfC;R=auG0O4nGid-6Q+3>|blHU)V-)+W0bWYdDKH zJ+osBlt!(3>~mN-&j&48iqXf zS#Cln1+O@Pymu%U#t+8xU3u9w9H2ilMst8e82M0k0u_~0%k&l|KKZYt0VSP-iF@E) za3;B@QK}%%LI-W%ebJ&M*Zx9a1@T|>IC$TIK}`7*4AluVOsNI$-KLYlhBo(``d`*x z#8+HVo&v2N22;8;uku94e+mW(7~ttAkU zkrzIov9&)*v~MI$Lcq~KF|qfP0H%ufG4Cb>9UX$@kjU&2P9jPs3`!(<=59g|2R;{k ziZ^fovSZ;zHwHKy2aNI3pNvvZGtdmcrBf{usBtc?HHwh97DI_gxbz;WnO-n^%o8Dn z)fHf}55#p3Gf^RUG;m+I{w(ME_|Kv`&atRGpY!Y}PlW6rt&HFlxo5CgBzR-49&<-B3$VsPg!^6n#a-Nl zOu9tXt;#&E5qzkQz;V-!g!3D6`>H9dl@0~ViI6cicgG|2SjuCqI+2}UP+o}P8Bpf{ zCv=O{C$4Vd6Pjp#jS{Hx9XBn+_2VWw`0##p=xsteIy3Z6SF`$Z|3WHf7yh|h4DE%8 zD54>eTS!8AEmO{bmUZ>SMb0h512@MQOe;I?CNA7t05C85;l|XeB-bbLxZG{f4v+H) z-O7&JaqHaBfx##Aoj$Sse*EM20Ep1$OUjxR zMP3pKA$+aDQmB!-3Ujo!TDoD^WtAUsNyy^4m-#$>G6IS7AW<1NWlBMf&LWY!`mu*4 zxxo2Vm0(>Be%+9Px&AQaQJoMY5R&ffTO^h7O%5XFwQ)|aHRf@I=fY}YjpbsDG*{q@ zPifOW&t!u4(u7WdX=sf0i%R|5VjFNDLmIzNUn5fE^@T&C1Se3 zWgy09B8qMDhp2rtu>U@c@u}FDQ?!Vcd}9j{N}a@@0ENUU8FTdI&rHn?>vT+&S}jNe z8+7-hsON!l60ZU#b&3f>uG9(pF|!7bbnw?#kHUm=@N;6tBk(V+=rxDnw}7rG=+6TZ zL)bdsdchO;uhYw~v?joZ=&?2?pht^$KRjdFq+2CpyWt~N90!2+MI6^*mGqZedirDb9T z-5)rSY)WaeVV_WPg2U3wVYW~-usXxpK`027d4ct6|A{Mm-FA|`I;cx21TyZEHa4`l zoI;(fI*d=y+RS^rDI$55PmlP!niMl=Ll13n(0b--DTi5>P^AmF4yg2Ds1W@{{!kOX zm_$7L9A&G)^%He~w6E){_py=M{NN}aiw zCfKC$?r@4RrX#gTPmhCY1NICPrg;X;$l)@Hy3ET99aFTLmK0i_3G8gPFWgW>!Bj_Z%R~zM;HBVRX|GHv!PIo<$sKoSn@(tM|Ea#uE*asWzK_u`={Jz}< zGt=hwd)!6-yLRwuy5-z2Vi8RQpXrtXuOs9U-lK zT@FW|F?u?Eq*&Hjv0MA(f!JjC)=M$YrJzD_M7nRi`oPJ1qIz>YR!v*bZ*Gbr9Zf)l z>E;w1Q1I_D6X%dmkL$5JfG_hFnkui>F|bbO$xX@}vS?%wanr7R*=*;wpmw{U1B6VH zo^*=zK9)q4GNfb|oK$NFOFA7GvrZbB%Q|UM;kQ{-93@;5AoK=#$tokxvKn}s3c7V$ zvgmvJHj}OGYZfQSg>REv4@3Fce3)YaD=CHq>%fr-`fQ4@pkBg!XxF~wnH|&JBd-p! zY&WW>L6Dgy3~gfblp#{}=V`LkoNRuw15SR5gjej@Sux4il7zcFnZlIEuW`90Mw7h6 zjqc*;rL*1XoExc&AQr2`x$%hGu$k`NMuNF5?U5f{s`hCCfau0rl@3kh@x77^ae^H6rKzk^z9jmC6%}b_viY_ABJUA- zRs*3crz$Rk%#a)8SW6@Vv{61{cT5^x$(CyjozaLa%u%Z!U^4D_3WxRM(gh@jEH~Eb z@YaFSsXHz&U_wA1G29a}j-UuR0?Za+8bgg8ut zO`W)BqQ?`am_%WxsTona#Y13PXq2nvI$kghC7>#d{vf8_YkBYQ+Y;c!^(FiG|E)bx z>yZkl|2c+*o`$CDi~44Gkmz4mJP;%tYnt^#W`Z{YG@PZBXxTdEPwq>2N+jh=4?i-+4 zGl(gTxoPiIjEcHIz^V&p>&&fcYoXFB6(TLgVUPTpJBL<^kUh02kkjyK+Ce$Yq1vTH zyWGUFfiS^Nd}_i?_P{$QCPkhN(v}sRY0gvYKX)Lk39{#`(j!AHd*HZ@fxECt^a_af z8F0&uTx*bzG!ahe`l3yTMB%}M^gp2!!ZJ1 zfbE=1UPYucz8<#nnPdp!{jOXWXwX*zI5q1J`I&XU3B%Y^tQe(q|UOEgO4f6E*J8YB6xe0IF z_ackJ+r+uN8rzQnye9`)%4o#-9KuXI7VaZo{-&>L?aXJ6b02)C(mPV|`-m9+_tFX~ z7?ru!x8y%$!=M6$Y-ky7<sTtI@EX0UXW^b(Ps zty>Idx|)-qp%|5r;GF0RR*GKJ$f@huyIb7;Eut7M$R5+F^O_okk%!KY>q!vU#HQ3K z!u{@+#78qlVK$PjLESyjo7KGH@Hf_W8UZ)5kai=pO%3KTBS*mx&MLjZ7qaFGSURAt z{fdwlGYznbNs&Oz%l*nbM+?=iu?Q>FGZ0LSx#HhD4O>q}DVSAO<%TP_h-XR-a^c1= zGNs|rZGcC1pNO;WwDXj)Z~vA23xG;{s%vVO371D0Sd2W+!lQWj@r30nKIEv-Xqeg9 zHQg!$OBNve34+dyk>HKx`!UGB#H2T6BINvGswh5>KLx0rz*vWC6qaB|gq%f!!~^4i z1|X(Noa~pE_FuGS_~?8T^>aHKY0ob9ju~3lT*1FT*bw&5NPQ0dV{Oo5Deoi;nI()1 z#V&;?b~y9Z&JP=Z`X4(66n%CYr^y&q`y58o_z=kJu8rALbg5;|01U~pMuCTu(j0!} z=C0Bozm7MWZj`xalGTUqxXmT*s`XRFMgKE<; z5g2cfrU6)Yf+lIDIAKeOim2DJ|5^D z^L1KNq|)qeAba4^R`ox@ywD#38ee9tN$<3~J3R9RA1~BBa=)){wM3yK68^GbLV_p% z3I4ZX+!-%4xWO{zg%c!;l zCs_ud8?utH&acwssK1M%J2{7jxmxIF;XTjjwDb49?N^98Ht= z%kxY)DpXwka13q8Gj7+v_#aax3jje;VT%l8w|^Caff=RH!ifGoj%!J2Wmo14;_qWm zk*A`jR}Et}t z!%Rvdi_hh7(y8D|;ft!UGxJH`^msYYjve@5n2pQ?XL8cNP#)Z98X{|;qT#>DQD4$j zME=`cIANXix2f>M3i-1!dV%jfX?tZ@n`w*&5!gu!_putLK+-CaC-}h##ppByJlCEL z?X4~*54s43&XL%X0uGFZf%Q2Tdrd(##e`1h_1zfTVX@=(dq zFWxlK@k{PADtTFY-WLfsWr)0(tDTa-b^0|ScnG{VrEmW?=@;E14<2|A@-PS;`GDP{l)!1&0hRA`RlX5(TbU)e@ zVmuc&KO0&a3N&HIBcRNfU&$NW?O1n~&^0mx1On_g;$}mPG2=s6nkB-vI!h4ex$p91 z?%RL8%a$P?wy~F`D7y2JSU71BN4?+gw0xo1mJzy6%tIDK!x$z}?QGg8j$5!4oDy0zxdcD+sYxNn%J#e{OmR9!F#dG|WHZCT zHTJj%nLUj$$PUFF?PK$=_zsfw%Gq8FFWa|vca(A`2eG8Gp@!-;`%!Tx!{*RX*zbS) zUicqOQkSkD;0+xBfcF0t)BN|_(9!ijz^3|^?UpEl&zc&{yD>CXOfQtY0-H<} zkcA>M+$RFabEb9%v{Ki#uCs-HKK{a=>ojN6KPZ%v4N2_$c$OISf11p0%|g+tR4t%K znUhLXsq4E`$F&d+9!j=n_EoGx600)?up`iuB)m1WwrqzeO>0;$r z3EG6{0IJGYUR1xCJhy9x$w^7Iik5830ykM(W1GGoyg2>zyj5A^>Hhc*X+xn6o7(fu z0K@~F`E}lo7j3o}p_0wS;I&OhwSuEjy z(X{h^1}VH}5eq1%KUl_bxh!ITSUIwgU^2T$G0yW()@Ltp&E|2s zvfI9&2%n<%glq)^k16I?ajRLTWzv2@152u*KL9l&Wfi-HU7VjZc_7wnT-#7@3aeoh zSPQp0R^4yOo2jO%LiFrVw=a~abv-73jS>Qp946S;`>K%g~4GJk_NTtV=Z^$1he5(sNhfLGV|f{=`a@iD+!r zqcr}bRcsk#zsT~nU1G@qp1YTVb6zN%?obE+IViU1`Y3R>z_|r6blG5Ch%Gy^GoHv3 zQ31ncp0ZlkiwA6;Skq;!#17VP%QCxhYnf^T9*2wH><2YwPCYKfn0gm-fksvHYh*lq zy{~))*^g?UX(;OiMmG70!~036pCkQ31LHCQ%U3kknBW6U5WwDWy^$>Oxj7at)L@CY zO8HA;74QIsz~~V}#8B{1I&w}I`}?`%5hA&(Rq$!{@a6-fC9fc?{%<3^<@`1$?U62X z^x5IJGZw;85T(IDjHrz55W$lC^H1V5$j!z(4zV|=I)W`yA1=wa~W z1b2=}@#2N>dBkV`v^-8iU9!qRrh_znQfjB4j|hqKsNmmVN{$#G8cYRK#NXG$*eg}z zPk`)3^oW+Zng2!FH%4a`W!uKKZQHhO+qRubDz4b9*tRNmQn78@PF|{S>-HPt-hTal zd}EyN&)#R8v(MafuC?acF_CZ8GF&T%ePp2-u?b6l1Ue+p3e{Xm`b*?Yq(NgClQgc{IiL7T`-SOSl7Pn-SeiAJ3E z2bj2a4pES1BWj>`5Vi2(bW!8V;YWlx9DWSE8*sUHVh9s)^0~OXexhj4v2+{7!~By& zIbSichMnn>XdE$V`vCdf^8P#s?dQk)q#WmqK)%tPSGS$W2w>9nlc0X7({LJ|!5sDB z^Ttem6|Bw*6gF>fEuxy@XIJ9!o!#uZmwBkFeCPHua#i6cCk)lCvM(f=*Y1NGE`p80 z1u+ZvnvwX}=@8R}V#M*buWTZBs?QHW61<{KWWe({hso0+M#sx;OK@${jt33VTC`=JT4{r5MOJ>6`rRq>HCiGZ$2g0 zczSL=0sm1I^QV~SQiUXy?8~4|_GM82H>zSxot*5Q{9{rA^{npaGvEqt3#!Ev%{^i; ztI5ED;k2h#66Cc~B6Ztwo*Q7{u&)x64NNI}SHnhvc(m}1FiP;RYP>Q(ps^)En9K&& zCV2;u%=h;Gw*vWG%MpBI%4 zOj?t(o^{pwF)M%n8F*6u1p1F>{b#p65Sa_z_}ZnXzMePT|Gr!QOK$+vxE{Mc0+^6X zo?v=Z5i6&kRIZ_x>t08$hY+Blgoq{G=eLuPk_i@>SN5-u<_>+lWI*_pu02qMFb}bD zc#m!ii2!`Y-%4S% zDU&P<+N%??Kr?Gkj)f{XbWVmIw=>%YH1T(5tkfBJGrOdP|w zXcB%$J1@Ut#Npdcza2sYx}J0;%nZsxy7t;Y!#fXjhS>)Lk|wMJcIPsc9FcbfGYBEi zhNKQUOp0o;+TmPe%O3aJ5E}h5<+$CNB`$p}txA9g40^U!#=Fh?O-bDo=hxWdcoRic zWA5eja*)J?=Us>!^px)2RHAvN9x4{*t6@k+Pmv*J0GG3fwxdD!-TvNyV4J`L$5}o0 zF>p+=i$djC(d^uc7EXy*hgR$cr)Gv17_UM`=7;=b8E(5<-ecZ6=QH{~$gD6Ld_7)X zAv}uYlMKmI7?0=<{M*7HfE%vo&lcEx!*j+f)g7N{V&lB0!9;fo>T>Pl4q~tU)NiF&NH?`WZEbYj!Jf+&7 zB`P5!Cr3*+@mpG*VnjmK0p?0YNofb@Ul#1wjDK%rB=~jxztmj*ncCRG(8XEb(9T5v z>&ni~)W-Rr@8+M|9sT(tCgmqmkw5?d_+S74ME>ImjGaskT}=N>_@_D2xZ3z1fzf$O z3C5!s(Ay#;52QiB3e>>M5|E!6^ety3sb7p}dB3g}0is4?nQiJ1xKlOIDq!t@3XJ=2Kes%vzRhL!vsG~DbcUi4X%!AAw=S|i3^c$Y2*gQ zy!q4Iw++d5SRjjZJ>s{%n_BJzPbmLvKS}+nwq$VH{}?V?YpvpzCT1I7kF6JA;Lil< z<(J8Cg{+mo@kR0fF_R(Zm~3tt&)n7gIDbD2uJvQomOK(EII6)Kn+2Uu z<9db&8rLZW^mu;gCnKXIaXY+Q@Q0(Jw`R3Ezk@+6Uc^#Qi1Z*M&lseD;+PlWrK9VkLQ0wA9**4NZBZCuz|qAivB zQW0cD<3+0dSpDeCN$=WNT~%b3sy(nxet{Rw`%YgvtY@zt*Rk z1Y=xQ+Z&pd-mR0XTkeXb1b2nUeEE1oPVLm%vWA7Av0xCor^+?#nYl?Lc^24280y|F z2}tl`u4SuY>V|g@URsD^-z<%K`h1WtF^e5w7aP3Z|vEqdZ zfu>^=&}=8GIsdVHF_09ZsVN;BPt_s5IQ)rtC7LVg!scG|704oIsp5?UaTFStJ7^y< z(PwakMjDAyAWAXKR@K_a`Sl#Jtc{}yGMp?wQ%{6`PU~egbizl;-e@K?C^Xf+<s2-#a%GVp@_4?gq< zbLyL90s6moU|J{ufd3rS%uQYX0XW(}R>e^K7OOdqB;l%%difxAAPDb-Bzw&sEg^;C z#G0_Y_kKsF>m~=AB(T8KCJO0GAMrahSudE-KSSsH&oQfe;?he#l!9SfPNdmSoWBl| zmXk9e89~jPXfXqB+S~H_kT6YO<*2aLvR58WX?)O$wKdpCn4>ea)YM&{HmfrsHpEb;F~_sR7tpW8v3T6 z9MgDc1e%P!01u72zP*r$`E3x$5Z9SCo0wQ^gY!(kN}YDuAIo>T)8T>erFg1Bg?o1b zc`QQ|DL&)SZ$$9M(s)v!Il-S5Csxp(yvPpE3Hfw~iEAJS4CQwjh_J+T8>#?iBMnJ? zC3O*9KDLsPXPcH(Gg6@=Q>63Ids&U!w$VUD785PrR2_`Pl1h(_w20hDR9uTVs_9&qU z3w;qw;nArQ&{f7e)FjUF}kNLXs*%L`kBxnBax;c#wE|!RW7GKj7yt3L1j7^a(-*I>n(nM4F9vUCNUAkI2TaOzps*nV$E6 zxLtMoHHb&MT-w!%Ri*v>Usu!LnWvatz@F^HPNRxGfbzTh(b&9;RSvD7iHYOc00S9?fwj&j($@RksLB<07rJT=7_&Yg5B% z(h%OUvtspcE`uz^cC=?F_pVn5f8jlx zu}T&-Ujfe1ubz%V|1mB38$|r!@aGzTBPD1&C@S4`(OWtoHNmGCwh@DnG_NKYAhcB` z3n-;dDbY~`0+~2Y5V5}me&qN9k=7s(e~eJmY?jpXlc=MRQeWh9&V4JqpZML(Tz}gP z7n)B}NO473w2grM&Vrc-EG15nn3&z%jPG75&rD=_XM!^LJ+KWed+BI8EJX55oNXoC z&=4b{C9X(P3Wx3h)G!9^73X6q)**TqCILXazb6n|c4Wa5EY+(6I2&n_|E6zv6Fxuo zCkhk4VcSHwHI^-(P{asDIOM|$HMMIHttjw}4*(F7p#u7O#JUpHTCjA!8(TZ}DjU^Q zYZpXOh#^Qz3{SMrQ@=cT5ItzBDZvvV$H}S_X*c)GWV_HxRo1W2wUuaR|NM5keQ}OT z$WX?8q;v0x9{eq{==ONQ$5$L)m&enUqt}V=RgVt4+cDVMNNhKd_aUhW9GkbLhmXgR zWulQ>1A*VAQ`n5ocKzZPDm6i7gf{(RJaR6O(pPwz9=S%TOZiE%uwX&5`Itfa>`B5q z2FCy|Za{jl9uzYbP~sWL=3=~;;+?24v~K#bCvR}=yTk%qBc-gF`mO0OD~(YoJ;`WG6}(^ z`!Oq)1R+Z}TdR_i8oQO+8G8i!%{1#9S~`58QRa+@je?uC*37?M#U# z{!JNN2S3Zw+h`5f&t8UTHfSZB#i^F_@b}--c+@@xQ&_lzP z`%VQPeM7$a#C6d|sW$aSvDFfzzpRW(p;jp4ZrUn!q^njS#fAQyx5C7Vbf}Dem|tpN zvA8U&Y37Ue4G1sSPY6GE`}#d}vDB`kv7}x*0C%R!rEnQ;00QMo^uN8EyQKx`|tit?Pc9@ofmtDdOP^m_b{#FHtj$xUHCRIPY9Lxi?^4H!r99 z(LqwgQDiq##6}ejdRO_Ri;pNeO)YN^Nd!D zHsDwOead(3u|CW#y{@}79<|8WnrxzYZ}pMIEvz)-=~C@XIp&91RB@fi5T)SL(C5k!u;1KazK1Zx+%XhpxMBZ+NnHgdQ1vN(? zW`@xnf@4$Rl2#4{QJnCivBTYa3Xs5r8)crer0Cx4zJhtD_3r22?%h|D{)daX6 zMluAPgzHxMZk*#+Jim7Ewd`)>D022=$MKKzZhyav%O#0adEK2ZZ}nF5qF&N{)?gd2 zWO*6TM+-GSV|okkjZ2iW8%)zYt4|9(-@b?AD;`)>Xm92l?PEFfcUHGjr?XXT-XrRpyHkq1>5%x7aTSMh}P?< zQgn*lVWx)7O4>7cAKTR}MOv!PriD-S8?BT1)A;1$xB@4A5ks;QmNru3%tHsB&kg9&s9W%!?|P(p+_i;59xE}-R`=5V zP&N`L9TPv0zZ%5xBe(Pjxku)!wla|j6OqyBH?vUfCf2Ck+(k1~xrphoD+c1pF~zNN z{&}ISQuq^<@%h#=0biBkd&CXBvNFG5b?AG%WN4W8pMbj}$(gNZy6R?-;&@s@YFx(Y zKoe-1R>F(wv-ri)y2R1z))HszBD~gIEjs9?o``#$UO&S1=g9A|RZBTbMBk-47EuL# zVNUQ_{JOiwAmDWPav6G~lu-r=bDr})Obf4y?9%&+#0?k#WN59zH4*o>xOm+H;kD-M zMSBAECba{ZD)q$P^ylB7A09&5u2D|)vQIx1$bc}gCn%S{*^51@Ayz>fAY?jar?|wg z>$YATT#ULRKcj_K3B_-uG4jj;FUcJ)%H#P0bHv6xI^x#I+Ehjr|G;gK)!4C{IzKf) zZtk!fF91yl8WB8Qz;VGdhLLMI;z|EL(RUVNV_?wN3MPj;h*=hpxIIGuY^wBqjko26xm?brkg{RP~FO@bo-+2!nZJzwL5No$K8AG zuk~rbJQzziCB@kmFU>%dWn553T?}O_d~v#{CCxuhARy-z$9h4c5=&a|iySJCxttNF z68{^DIk4I();MtQ<`UB0g_gijp{_z=jIu1&B&wpPq9Dlh%0Oru!3md?PD7`u#c@{( z6vk7sSFXpbEYw9RLWyrpIy_D`1Au%pNkk%c1o};tff56b7KK_oLy~V|Nl$ zdh?svIS!q@QNM&9nTl4y9GmcNnr4)&wy`(PU2joTPlq>~4z$@rlI%f|u8%8ckXx8J2eo#a$DLl#K zZwFp*nRS~?NsH&RK#IxW6~;kuAn&pu(mdS_MhQJTli6F(v4b_(GeS_(8sSykEv$1d zowMY2b4DZA@`3DKJQ)sy2PUJ-c)@MS*BEw{s?)^P^1u#TK?m*076UHw153Te@*Njk zG_tth+&GYESu39Id8w=(uK=Is zTv#VE=AS5*s7a!e5^3?=DJtkt3S(Cb^pbhdIu4%-%AZqHO`e#*mzr2}%uxw`C-=Jd zP|BVu{A1bWX=bS^5dbt+{G4^m^B5iHkOu*GI_=s9-x{wbdm3vcc&AE(M^_yujo$^+8_ zO-qZ&m*07QO$Ib6IK23w!RLPl&JHYg?Yc~NRM!ZaYc%n@jCJOk(Q-eRf9Ll8Htzk1 zLQ8g8zNtn1<*K;Ru$s3~e@tqwT#2%RyPpx+k+4l+XjdeR*1%w-qY7FtLGX$evCVo+ z5-yBQe6V2{CLl*CmV_^f#`m1{c_VPrMJKnaymqm?DQ@8$`aHCP(x`FHY?ws2P0%`^ zzq#xwA$X$|QoI$P)84kqJ7^-Dqn~S=YY;VDT%S@i^t7@e-jZ+Bx|P$lUyGXoNopPv z3@PRU8{O8~gtmfvVx6x6y`ZCg-axtxi+F}Fs1RPDf^O4eF}e8ul9g#FAfeMB=nf0U zI-f6D%sYKC!2tNXvDJ}vpWec{NE?8@=FPnFD&EKau?uW6C}gK~!NW-Em#6PWg=)t- zYUFCE^N*^N_$XEc4~ZzTv7CoKjT){Am`uA~xxor@O%tplQ2hr%JVp|1|L&G^_5gX% z;dqL3Q(~8HqE)+`P;y>kJ9uN1r_5g3^AmQyUe4*e;th= z9Rb7tZd$xL2lQU7N+Xam_UcVXsBV*I8%nbu%)Mp*@1*VCxL^V13&}40JbR zjd%x(GB1Rp-K75~wXm!kA7Al;0Em>r-1q$6nXA+z?vOW!Q8%3m4a$#$cY#}?ku)PM zSxmNDfw8b6K2QMNZk%*YG{HM5i4WZq3^T$fRTogUzxOy-@7K$Ka~-tLB*WALMuj93 z?MbM4{^Cu%;XZRf7&&QTJ8Qv9Z%8R3T$E=%Y0Q}D(t!6fg69f=KYrhGF*Dke>DU(J z$P3rwiB_RaTq&F`>A`t2HM@qxQ0RdzaViv@p4WIg(5{}r>*a~KNX}#Du^ZpH^v$lE zQdDjScM-C!ab<;#u?Q>YZK2tIqD8rnsp$Z}2{jiAHa3WNg ztTzZZrLTMO^9cK0Qvay5a{-zc+_$`Vp8A*WiRV3*Ji8ZIxh&j!v?Ez6m8c?kCHePd zsfFJjzFcMu3a4IZWQM#L%*j|r;^!)A2@?^C;HB0425Rc_p7&~#_pC=5CyhT9+Z3__ zIz{$D{Ze>66v3ej1Kd~yC^|t@^i}<}Iq^3ZgMQ@0XT-b1{y-PB@b<8|(_QxyjKZ;vfiTJjr4wt%Oz`(L00ARWN zxR!i@Ai_EzjeadH48wZNF@7)VO=@~rEkw4l_AcI^_=X;VTDFJy z;Gw6Dxz-f{N*eL7Ar@#ma-#!BhDha0_a`-UQuhjqPU*m9~6yA!nvtn}e=`l%(yx(Rhm3!Gwj9j*DL*oIhKi{OU-y96?*} zy=&PcH)Jt^B%O@+mKw-q2*GiUjT~)_v;#CswEf*F=(j<5K2|C$8akv;ig^hHsA#wc zVp7!RaGDtsoajhzvZ`4Wjv4Ww^!<}dH;h*X2*_)riBdpB_Vy~*At)V^iUAQ_a-Dpe z+}WzgDo`9SEAX%L)s01e<6=k)4s)FD`1D`bqgIqm9ny$e5`&GtirZ{W&|4dy2=_TJ zceAnnuFd(`Po9~Sr?v*=q}gVIB1QIbsNh*s_mm!2-61xaX{46OZT9V(>k_%^W*h$h z9c=DA(YJHIq}=`2fdB&kG1#~|*w`EXrLAw4>bTvk07B<0r5GP)2}VDoQY-=xAh>{n z9E2v>Mgf@l;#pNLs*n|Q7%&8#4&n~1kR?Hb>?_nMyV1iWo2?c}-a?(Z*x%=gqiW(7yW!4&nGuKxX&&3$@B9Y0Qg*LETvf6Q?C9KgmeqZ=_ zf92B4;JyE=gcy@@iiTdIH=F_!wV%5)y4PE70Y|`w=$B|dY+z(00VZ-9k8j*f?Nl}V zXkcMl7*KaM!GHznQP1;OPM;?QiT-ph{|R;@_X2-W5a2HsuXkv2k*ZpnGhq!T!oDOm zWsaG7tG3AaZW%efu?@H}fWoTAaW;xMw4IBNFz^vuX*XIi7 z0vW3Z8@sJ}+o+uN{fagh$ zx9W!IbyMy+#@}_+`HXtTB4qr@F6>@fxoms2^3~lASn2EnOey{6*(hVLXG4i({cOHq zJAR%i?^)w_CKDATD)6W@4_u)=;upzG?6n;08@mzwTqLa8SYp0&GhByrmuay4zRk@RVAXZ6@Kr^^C^bbXA;( zpBB|IG@V>EvZ;7w*RqBK5 zuGkTLeMD|Y>hr2$-~Q{Ou$3S$%fSfz1(5WV6jLf*6XMRW zxX&ukhBPgoKNU4;2Br#)lgg+{5lJke>^g&ER;Qb)T4If9UFOM(kFX+saUrz-suJ>B zf;lQ8lF17S{jWep99tCw0yycF1U`Oji;OM(=HlJ6k=J3Hdj;Q~7bA4pYO@mn_vh=^ z(&gLqQRw$076E(c-IWdL7W#7+x~`ZkTjzCn0^hiUnV*;|dv}t|h2fOSMgxlUZl>WA zS@qG_=4SGmOS8>qBZUa7u1Nn{IrR0#|2;s&@$Y^9rnX-nyQit?{}>_4Gy^>B`+^nI ze?LO>k8%G9vA_NMs{~t>KLfg&4r%Tp1;HH*1K3 z46s>Q-=MiGO404@3}~*jl-RvP6|-+J{~#G~6-qD1vMJzX-h6)TWS-FA4ACVdi;W>C zMZTInIM^j8LPULJGDV)1loOxu%9eY*vLL#NClkeQqTuuR$y&v%#)Ma9?3fN8tgU|K z{WAc%&q1fCV2g0NeY%fmYIt$nhM`~{ zDKU(J{_6Y?K60&gksk=(%gt+Lt`TUJ*+*6c^5Es!;c);fzK1M@p<=XHP%!0ksaOF0 zXVT$K!W)IT6QTSb&K^2vIsEm#%)}|N4_C@%Zi33uBMTaFp3$7>85E-=#${r&HjFN~ zL(y;plS|SZsiV!(g2@tF)S3QFT5*%vdVy1VlHkFZapa5hdz~Ncp%dWEFTVIoRW5~3 zz#Eh({A+Kto=#};z4YR1gb^nIiw~WyV>8=?31$sfATZ$Wu)HEv^e5I9l7QrOLEsl` zddsO(Ph1k+1G=rp#QT-eiba=&F|3aennjyr3Y|J2{nK|XJUZtbL>x=^vR@MRGFp#L z#xq=`c=<~QOSzv7Z+w*7tYvTeBl)4R;%6_yv7)s}hG#`d&!cL~MDJoTaUvmoJtM(|xKp-5-p51#w)>c=Z zRB_Ws=ugxH{OhMky!CZ8W!n)+yXo$TjMpTb!93=VU}Yhiu=$qy;JJwzlfJe-))Qs6khHRxtNVVIywVuM-E`YSC) zQZxL%gK%2J63AfBQ?vyjj;9a0i-OV$1r{Uhp7gh5##;zvgY1=-i?hk=i{3)tTFR%v zvp%(-LC4{e(EP@aM;GP|)ok>W;#q7~IF^RipN?u+&${>G11$Ej#ZhN%!svwY=#q3W zQ&WjTJ(iY(Z6&pua9+8zMh>UR*9+f{k4=nPjn4ddp@f)4fBkC_?W!atkl&ZU8G;4? z_&4J~e}e;O`hNz8KMBflwg0kZ9IDeiAt(TjaRJ^4eWMLrI06kuUb;y@M2Kuj)RdNX zbx+fP0NM*A0@Y&SpCYp85|E|szZZQD-p6+}bN8Gcuv;mHLTF7-%Sv14bQZ&;AKX(I zg&Y}52$a4t?eh1RC#yq|3*q9-+OyHHzN{;izmPT2t1;P2@CAb&svWiciXQ{5p%p(1 zEI7INpJBKQB1Ha3j22-iU@F=jDM?kLGLjo8FbEuMZf-g;&{t^H#Xi&GEx{I##X@bo z{+QTs+azzqJs>M_!67fi3};-L-VK5WrNgfNDZE8|L~(m>CFE%V=bF>}N@9Kk7(Sdu zYaI)7Z1zKYaH~E3<~Sla7Kc_QL@vhX4zlNz6QDJQ{e_^R(~}8pI|7c4&-26u22N*q zMwIiHI!bKTbhnXa;q44p#|af(JvW<)uh;nMFeq1!029DAzyveNacE$9+CjkyXF-6x0r?el z_=|O-_Ip@f>jfym!HIdtHfx~2|0DK}AkFTB%B6={nVDEmvBJmE!~!ghlgn!eovBC+ zatS<;yN%=lo!n2ftVCpcScHz)*h$OeL}E-Jk3hK8(7Wt2`^E#VP*m?AWqOv@GqTp4 zESnO;T3@jkau)(is}&X!eNz!UrEgsRAdne!=nVRjBQr({(YfT7RvDQV5rfOG%M{?E z-HcK?H7z!8g9|8T&eYr5^P z|Nr2ny0-OKK-+IqpYbdKB{53-g+zgnHK1vVjAJ4JIr;uVVnb|2)!i&36(MX#2tv*p z%2x*RTw33DF+x>4{>(1xj9jP&C*GW{{+Vl|ev2FwS@rMvbWB(b%Abg3!p^7tes znU(Z#L2#?@ToE?+8ng$|inP#z;p9*40z;TZ%UGPxGr$yXM}y`x-pJqv?LrdS7Z0B? z5(NxRI5{1cVMp=7e$)I`1COx}x&F8)Fv<3lhvW`C@p$o@1G0h`7aMzyv(U~^SLYvg zbh&Be1vY%>nl3Mn)kDbSTdS7UhUJ^{I$34Nt|ewxd4n>#C4Fb0K3Qds4@i9D^NiXC z{k0iE$qs2`igv7rjz^?I}sD#uj5JuBoI%+X*oI)Moyzp`I3n{*1r5v)9UQTRQH88%t}ePBuU z$S`Go-7pIdcymS6lBPk)+!Q@Yc7wtoZc%J@PLgz8b@)?#FT1jGUIeZf;rWK)72OdC zV8r0p6_!sr2fnFc5}?rVm^(M@YY*!v`=?XX%{cchF3To{2UngO&wvZ6+>g=k|CZKI{#FU7rFA^qYt{>3;6?rO+GiqX zJ(+ALlh8)b7;Vl<&giXb;tq}=g8-AT)wdY}(f4la6M#+~h&LW3t=zu6Fp8~5;UTK~dEtO3@^&2i8V~N3*0`*$ zOXki|@qG{cXR0nmDtavolo3BJKqwDGdF-_G;18gt4S2yV5{rQ-Vs=^w-Fz&lrnG`J z%4WO{P_{n67-i4H(n-r&6gZN%*F@-%f=3KL;QL(&HeQHsL}Tfb3^GjYm1(B#7#;Zn z`1X-9f2@@g_TeXL6QH4@^tv(W3J;o{x6EySjrz7+C^2 zb9^2t=vTU~d_A|4nOGFMaoDcFk*Zz}=^gCa7AaX1do_bs{?F&>NjsB-biFx)*n>W9GDBArEBRgddr8mZlw(Xuclt(&@D(3!#TF_&k%C z?i`aX5ciE7g~pm$r&r)VVbMdjd89{Vf=CLPej*dbQ-(j*xhU>03HBL#e<0&+dc+{d znajjJg?c}7U0iZ8Yjr^yM+7&{d>sjyKG#I`RYgIWCcs0=uQ)8uPTrZ-gwdf zBXjtj<{o_OF!=5@DtC*SC+kVuF52icwn%&;f7E~>T;@FYH%y+OJ?-o8r>e>CMa?Mp z_J_Dn0^@iFPxr7s7CyiDLuM|yy9b-JFCX2S>h9Uk)6$T78!l2FnGrokSfBe8t|;PVz>yv?|k zjLpCw*=-vaXI`sr9fZc8d1JPVq);%&VfHMC?Myl;-6AE)Zq+&UcMHZEYzkSzewSvQMvpqKRW9gNF)70(ag zu;7d7qe8hYcp}LP;w+!Z0!rXc6{_IYkm(Vj*}$R}{I5$}k|v%y?Ez+#otSc*xU-fc-_gG(x=jC>qzlDZe^~lv%deERfz=@pj^#jW@?Oj4Wn2CcIbK#)J&V5 zKXlL}Cg<>oM*JMzG60^Ozy)$p#HU!xsv;od_rSvCmegIbxVcIS3|mPJD0njzSi(ik zoyY-ETz0oAmF`${5}T&!D`$yA66(E)o>Yv2Qy>mcRRlsoGWu)x5gOy+uhYW_=~5cl z*B#t!b7jA8Hqy^Gd8`Yam-8cje}tGo4Qy6PL2GNYcc5KAL21BFy?-tvq>o{pm$i63 z7R7CtYdd~S1ZB^&^oL!xn2hbMt*ETUVD-#Wur!W2cX0vh>tFiK*)$|b@8S%5u~rK@ z*At1cd}F7uY@dd&HGTE*FTSh8VJCZoFS^M1MHl)1AJOHHy0)?W%RzmA;iZ2ejGFde zwj{s9YK*Jg9H8VzWpoS3645Cz-dL`H81g;>3`f%XWQimlGPXbfJ_L~9A1{S5w1E%k z!x6zHe0yCrZ{lC+L%jHX4qH4ez`SJcdgj~lR;#bl#3qhQ;ic0d$WZ%*1-we9Z1d7- zGOW$>P{rb$jUR5d9!rOYIM2G+3&c7YA!Hl!@f?!4Twj&HKhR%E{Du^EaE6Wt08fkH z64n@8-I9y@S{7lIFYYzcUvLjdY0iffM}M_LLk~<>WBPyN*`!WJ9S?vhWa;mgl06+O ze_XVoc!CfaZ85|EwEixR)tvnzNnU6wTV)F1r?gNLM{(~1s87lf$J?VH>(N{p>k zAX^}7(Yr3s0vwSxS!;m}`*h_@P;FblQ#&%9QN@?^)G?QpyPa!38HLpsQcBAdUbHw1 zW06C$a|r_otBj&ECs|;+8caSFjl9(4h$xo67nFIgR1RpE(WD$^bgq4spR=MBO-;sq&dVi zfNw;!5vI(DkYYq5Mo`sHu-Uf=%{U70z=|lG8r@~gR?rf3O%o19Bf65a(U6?QUId3i zQ&k34EFp~gnODcA5?_*6V?S{vn?>vzX*d^M*+i*F7&G~ zO!9N*u{YQ}SW=E^Y{S~{oEMxV`*4U^Zi=rvc9I)J_V;}-XmjM4N+X+nh+-p5dE%=u zmbhBJ;arg9(4y(bWDWiJKqpD<Qc9l%ieZS@x2h17`{Bxt#umf?sA{XdNwc}VVoQ(Om`h$U1 zMb|7f97nWkvymcps%Y8+a2iQ!xDG|f;Z8&r(i81;iCTTB*&>4j48Jz)#&0{1_%N0J zs|_-<{hiv>DwtC~`0PVZJjlRaX~W&01;_qhovCXw!Q1ru?Nt_4rbW-pO?MV-nFb)C zmWLLVGgg527X&hue=ZXY^+>Qq5{5BuePD>{ABaEy;H<+jO?kSfZPHPeKlTB9Dyn-6 zwox#~5ku~F=_2WVo)o=;`XP5C>_aq(^6kw6s#gHC7KBj%A_$-W2=s>436Uw$o$OS) zRQO}jq#I#D9WNFa*ikeA@g4>zmbd}zdw0BOF~q|+gz0a%NaOjBg)@%DOD1N8u;kexC$ znqxmQtvH%N;NN-TdKG^EY)E}L+!v%wxRNOt2&K4+cNo`UbAT?7B@$>Xl6^u3%_@Id ze53OX?1kG$4#nCR@H3c92-nUhI(eqQ>2^evl`aAg#~nlVW=ni5qj&kqiq8Lf2h39O zT>De@@#sR$l|L)$>m7?V%1TsNujg$8`3$W1E$q{|p%pKDa-Fe#i0Ud+`=!>UgPy<# z)#KG>@mV{fl{B6AHrsA#!>sDvfK)2#@(*ZJnkXVP*Wo=_pdA&#J9*4T-H+LYfshl@ z>fv~5QZCL`c;xF!GpT7-gKcUp89NSMUN)qj1r-89zA_q9f?wG0ZpPT*Y%2%@Vdc3x zy4H0U!&CxvTJzJk9pArJ{en;1an~d@#&og4q|zijKun*Ss% zqd>R%`)M&0S^=kdCuhnfcReUQc@6bG%8`kd6XYLzmj?y2W_ZpNTPuH|&0b~mvLF71 zJSnXv+eIH+UkZW4Aa`bpPQRCS`fTpqDV867je{eO{AgyRs7xd~&AIM9CSsag7{YQ` zL1vic2#BQpM$5LlulOFX^@fWY3mX9jmnGa4oFKwp!8a9Qe$V9VxT$J5QYZj?!9mf@ zU(-B*qbB@EJ?zZ_hYiFem#0iTQjwv35^9kQ-++x50SsQ8yL-%I+cFuQ(bZQ)LSq|Z-Y--?WXWlgx1 z@pELU;k>~jkTo3-j31Ix&2(HwS4%@EK|G|5urXhy($hWY&M>IXme?K^*$?8%HQ9+r zBbca!?(u{_bnqAL=XA0Hxyobaz_Xy|=mp-t55_!kOKx?GBSQ<%xP-}Yg0T2kZMrJC zVa@_A*naB)V8|&r?ni0`JMFU%$7N0B{}C_Rp*ID{M0&CF9^l<~#5nd)8(Ko?7{he99yfl#)- z`zG>oZx*9+z98q5y~{0vo%2L5xHc}zB^Zv77&=Y0v<5F2rG%$XjZsG3P&gmBz(z0^88vAxaZ#Hf<%=u)fDc;W%DjGwV`?W(@x&C;V>E{G|tMll$i9Zo}DCwNERTIr!p*-pq|{LFGf0KMg$maXCmIM zSlVwEY=z7NGtVCE&cdoB3UcH_*+0zGvkDK zd0X`xV{Ik&)GtMC_X#4Q2b%nu9T;0emUKlEE2;FAFI!hTlGtL^avv50bAk;8y8Oy5 zFhNs3@zcLJKfiF`?^#-re-9MCs_TtiEbZ-_^YE zbC{Ugn0}es{|ZF13#{eq`6?hw5W#I-6r>>l%i>6WOoKC>?~>p9D%I1r3rL^-Qc zzg4@r;o1HWnOhq{mB)#J=CWypKXL?sAIdASV1hD8*%1b?>s6F;E7#9+=h1P zdqey+Rn;LC?Po%W)QsR7>z#Z7EY*1vkuWFIh*}zgDK-2SlKtHAO-OAeYPQsS3synV ztLmg;U(d_JQP~xBt^Fr=ZWfW1|I<)Q%v791orlS4b62kqC4%rW@8uFO%nJ4IdJ z&g6vOnBBT#5x+Tjrw+N)x4UN_n>0j)r_3@;HoP8YBqnK?uLOO6@ir>P2^g({NVc>F zJ!SX#2X_D;bz8gg)%gETO6j=6`If^@6pqQb+g6H+A*r z?JfQyHhgVMn?=|3kV{u#<~fTCS@c_a2v;agUCqk8B;J*ME^XtBr#5=Q#ZIs3dp#EK zMjO}2TzfBB*V4d~K$Hesz>XE)CMZsa*hnk#$&SnUFhX;ms}7=j7xpB4SW9KgAJ3RV zRMfz50df;4hp=z)MuE3&fuxh958$KVobRYB0u$Gj>#+zdvi&jU(B&>)Yb>wFDhKVq z?geWm%CLC0er%0}eXMp4u1H1Lyhfypv4mNFp*^DL3&6*6_PvUr28H8m-V?6BZCU8< zi+X=+O*g%RKb+?GNM*HIoUBO6=mT}frYQTZaj#kR-15SrvRxhL9GnRSA~&+wxg1CB zufYG!L7PZR*PQlphA~m9$_q8U6Tehwg)n!tcL4200bZ?Duv5$HhS)c%pb#gfR>~*) z>!X0BB?%?-;d^=x+1?LQF~fN1cuZ!o8z;DZ-=EKG$o&`ewwTrgyi zPE|cPsH2c+cSvf?)m$BQs6&?B0~Scr`ZegivI_C#XxL(ubFrs@De`-|Eie(sV2(sV z`2HmEw{Labfpb>(On%eIov@u~&Mk7Syx`Rzs2exX9ziz>QS=C!?5A69{J!RigdRjS zOLjKXiy(8wQ?J8e^xr!6YuFZk3&erJ@ZgpDY+XD(vvZ1PlLgWLQdB}clAdv?Jjcea zKMrZm-tO`sOP)^Mb|#x&Vtu__LP`fa`uGP<&|k5FR(Ax4Lx6H!zyivq{~P7{>+<{m zFI#^fnb@tCsH|4gIZ^1y6E+s3Ym&d*8AYy|iQO&FSGO}|tYQQhvQZM|xzQGpKHyXQ z3RKxp`17}k2~z|5gvCXypk*uz=ka8l&#^SQ%v&w(AW;4v0tqnBrfzQ=8Bn4F)eu($ z8-$@Pe-H9)hrKI)VF{cE?bXoRpBlk!nZ*+0JnhTS1yTF_h-5 zjxL(T6T%fU?C|ZCN%grh&K%hAbzj3l3d@Zhihqr z_*gVNd~QNv?ZG}_IP63O=($4)utLZv&i-H_oIiV|H~{eyiBD$Jz^&r>*6=QEMV@yV z5OvzL6&_c_Q|Nrbq2$Kff*%CoVElPrzb=BZ0x`v)D{t4SJAYZf2($KCdA@oF&k{NWs^?Ae`MBY471IbSj-TI^POeYlg}^t+AAR{R^Gq&=dB1 z%?Y2*3y5|`I~VhhP0Kfr2}g0BLy9XB*^y*AhT{7V_AiO(L+sdu5AkgI+E_jix8TW@ zm$n=Io|}mS=s#7g1~)*lUfDgVNyrIERuLL(d265#lXR9&P)$>oAmzcKN>pFjMT*^7*0c9BQ!Kqll}4I{STv_F=i>!jqK!W-#-ESu}Ay)Fy*nr(Ry-3x^DC=ZueIp zT3r3kQXn@Gm#>rj?sKdRpF!-p&+cRk=RdpD`)d*Pu?ppT&U9LmCa z*u(ZZa8NJ_y#nlOqwV5?3Bc0-UBb*Q^DFfGBERloh}zX5-RAhLaP|~4z<0MJ7Kb>; zjDS}W$2#1_S~kKm{4={l7?aYv5z73QCtqFer{SZPt$2-R#6{hDcu0He66+tM+k+sv z6ts$<%^Utdl4SBc#c)Y;wjv$m78}_JR16f2By@MCuZEG(S#FYR%Jsz1Cen+|17l>amTp#!SH|d4{cFGxO<4}!*3PX5tz3H7{e#>iUv8Wr23dt} zir{Cld4kw^>j)wS3bP*VOloJp6Uui4W$WcU6B)TuYM7JSQByxQM^f<4EH6Z=Y@f$< z;yr4_haGLPD&^APim$g+$hf;e3~O@d+?`L<8X@f7p?*}E2Um~>kBRrho8&fzH+KyE|{%)mO$paDv~vu z@3HS)PN7eS!2^$*72V+UGSYFXEw2D)TD*?C!(r=KSF4;;a1E zTj*vW$n z7_rUA>{Ft^2KX=YVWA;Ld8`o+VT}NPPG3i;$u^5?d}kxl!~{Ibz9jZ0&c8FVY)o9_ zjSN>0xI-K>O~FEJ0JR|RJ|bNjQ!FR%m=b5>dWYk@9|VUS6IK-GP3pc7#D1vV2m{%3 zI1zO!9eRiamIHN)z!UD};`66naxCJ#;Rg&1($IWSRDDptHL;csf1-yvwCVbv0bt<8d?TO+?;6sdF56Txz&{7f4hRGDX0d`twdiq>CnPF3cQQL z-PAEY5Ow2~JP-%pP^MPvOe-2+7Xu|K@iXQmN}(2TjlKK8h-@Ida!i z=&E_Ck$4_d_FyPUgk!YX4PSwLtA8tU|6#I^H7MgmGi}5wkL%aUf5hQk1HxWg=T)rv zBk|G}vb4KWmzB)gUKV1u5yhS7CEtU*v`q0hMzJ!;N?Gp6mam|&>1T1X?cAGB+J@TJ zFQH!)Lz}9{(P~_A-yb!DZ)HyNzZDI<3St5F!8E7_#(>G=(J;A8I3{}XGF?u%Pd08n zVPRVYgK?_RKB=;*ZMp66xZC2_uHnhr-pu+`EJ~hhQ0R66!#JH!$)VJgRad?KjCjmF zT{01+Z=oMB`lS!*0JHQgA$Qchj8MD2UIHBGX-CAG$1qy{=|VnSLLPqJULGb}$7s5* z_>@*2L$#%>t=zMB&Lw1eTVln#=G^?VWhLL%jW*XY95y029=c}(fwysEAKtUQUu0xy z?5_S!tSPD5h`!;kSjL=yHU^znj9{Ycu}HUg6s4%NZ9ZG zkFtBO3KNcwSxKyRZqb9gPL^^{b?yth>)?}#N;?p!vO&Y}te!LMq+IY1!?8Lf_nY0o(mx#oNTS~ckQ$nYc|sgF<2rFbW{~M-RvC9^TTVAZo{-2jZ8iu3f{-)ll_UiMYkyY@PXAX#&-UkSXWj z7qNrwbq%ve@-N&+j^Is2P@zX<&)DafGx2GzBh4L#8=BdB<0|T+YEwEHPN|`bu^jhB z8a(zBUU#%2ZHTbP>`{3OoFEGqA=)R+?lqa3tz~fwQwwIx%yS%$mgC$S)3W=2AV2?W z^z`5KIolgsoBuL0w*Mb*&1Nb)-&O!ZxdEs>|IJD6e?Rx{QFwg^%fDTY|3MM`CR;`1 zKv4b*{}%Zd{%ul|NX33_6%u5T!9TxNDaYLs5ycC5sL7x&IZ;i$Tfx*MWif_y;IRxG zNuH}==fkJrlKHeRJJBoD{gWi=MyBHNqV2&rTf;hjY``1EMe_9Er4~-^ol(-DM=J!K z!CO5Ukym1YWJD_a7`d zn~tRL%ACQpo9@kz{oj|?#3Fl)p+Cj+`z|FRzM&;mg4WScqgdZ?3cA17d^9Gw2^fz7 z>PyBs>y_7td~=#1g%*q2TSy98t~BZM#IY1u)g5GSiuuYql0dRfZ^OD^hBnE7qX*OH zz)dN^4q#`#u|l03iMvLr5qL`TG{nTw%vZ9Gi}ApT--~FKSF3zR5>^Q;%h}IvBioV& zlm=~c{grjmm(TB86gOoecz08z%nnIOQ!Yt-Eg6oSL{36=87??lfJEt;qE4w_dTAV% z|63*a(9DZNW$=*JM|!zKDr$d|<@Y4$v=Te>`bwQ0xjMD-;ydcbTd-$ND+HMan;&|H5+`cz?2dJ?Q?_l--5E zsV7W6CXU%6h1F(>+Trne{a6A9Nb}G`J$^Ps4F3gW@~h@iA46jbm=8N z3rRlk(KvP)iVU-?{YmD=w}9a2;VPOXA`HAu;K?PkO^gCkP;PZEsMdgKc?Vy-?{hC@ z=_uqD-^F3X&eE$4m>q3{b53xOKM*D?k@0a0( zNVEJaB3{K?0>`CH+E9hTPPkhm`+>Ci>ySLSb4XZwOG=B`?J#4mGp>gH*#6C7D=`)F zsVAe;EFGH0f?Nzsy(-3RqmKz-ddK%(d5FvGa+~Ahs2hy^9KYXN_SF_K8jddpk|YLK zh3~mij0&eR9(<^(Xg%7Bcd>i_#1k5Lg(Eu3_-=p~6^?8D>&uFcJ&A06&eY*f4?zn960ipaWbh@nPz>SIBhT}|i&ZaV#a+|a#M zrE_40)-(>m0=BB{QYS%e1ejVP9A@nO~1W`p1vbYA)`K^(TjWOpQXL?7vp z=THz4%N|TO%p0d)l}*quBOaA5tgEyCG14MYfO;y3>p)?fx~h~sUYnN#64XKUh@Z-P zQiM$4?fu2zij3h097-VCJ&i&vFCFq_&6)w;iyd;Zz^0;nbbtCPv{?-iB~j{1&H|Dy=M7jx-T0A?nd z5I{ixCgtQm9}4JI>ix$@fB^qfbWMc;(k>i@B#`Rw*)_Zpa8tI6YV(S6q{a}u*j+IG zP&UXS1w`us>dKwaHJzHQ;wdnxx=sMy>VAqXLHmZmiju|8fO}7{FJNk_WJaZ&3iD93 z#F-on+wGF4xdTp)tbCV-HXt|d7i3>hWRzDts?gEV@U`sj$Do~bwYnb{wZT9NUoScS`7qGs~vjeeTrh3Q^IIPw+dU!o0KF*Z}w6KIZna) zzQ$@uY-T~fZP$WIK67{ma^HRaV8;CLFPf(S){xf20>p6kft4i+=tp>-m6A7MxyPVC zRi?RLXXc-N(Z}wp__Hh8_(EDzI8T-2e&tA$rk52tg@Oh|Skh<+wL<}F54eSO5HtS! z8@KfXMhsj2N8IB=pILW+xXC#&&jNbx@uMFvYnb3C;sd^7_Uv^hya%uPg|B!p_kb6{ zqsC`ZMG0le=pLsBpcVL3#r27HRD3a#nU|z5u|#8*(LYBYrr9!CS_*q7YLE8lJ`qjl zaZ}q}9nSbJr~auAR+$a9Q#QvWcvWKkS!V7&5h^y5!wpW)Y~;daqx{wQY?9Fr zO+_-a%)zh%-A!M_sw$42DkiR^A7|qt_D-M%Y+QZ+;$?G*uKlJ4IDEQ*0O|kk@cq?p z`-j7~CArCu(mkVuW1obIU6cZ&MIrL$pdfOoLP_|G%+kWSJ}XUG1hk?^7iAsYEUvpx zRXg$Qj9PlT)bvlhlTIINt(5(A+WotisiNwGzEUW#(WgKkXs5cKo(6IqMOzA0)+(-1 z<8hK?A_TjXH<9&z#M0X#&+6+|M@m)zV; z;TUvuozP?9)Rzj?u=aH@6QR}yNAT=pQj#EXj_vhmjhG6x1CkpceAzq4ZOgs_^4vR* z39t;crcO)CCZ45iML~$CMqM87oX{zv+l}1<2cK?*L>jgEAYkfw8giIoR?E8UC8$8R zxpPD`GNXbEun0?5=b2Zb*vA_hSuMEflY9l{h=twUeV}v|1!wBfhZu)WP84z~ zzvaC^ULgQ5+763>>LY%ZxR@}538K@LMr5U`m#mTWRfaWVK|8@vL84}@PeNlw z$RLpi-VXOeW5G=M78byC=fKG-bJc4Q5Ok(q&;KZ`+w9@N>qp&rjvGhbq`&BnJvd{k zKLmQ^sqEf;28#zD^S|s7ZJ_oPfd=5J#VBwzLdWsLmBM9yVJ%E2o#_c_MyHXWvE`=WEr4bpVNwYe=L>^Hjjz{qaS|NVPD>)OBFuf)n0YIt z7@C(&IZ;@GqQA={(e@2(xd9)82~Xq)BQr3Ba+qH-MY4v@bfaCf+u6Ex7kj%Se|k}e zg}}B9rti8xuPVdhRrNs@l6PFFo~j>dGTi04&u=J(TQ$S68A+oTYcCdck{{rn-wKap zHw$X!>f6k`)#6&dJ{QgM+$#bR~;S0Xo3(6Y@4;H-uL%mx3uvuf+~4`=nCLDhl~ zL4WmbU_qEUn1lZVR9!R~xNe*>F)WCXD+|YQIE!uuXx${@_n8||*VK9zO#g|Cr$H~1 zLnZLre9gJe&^XGR+EovQ4%ZlJ_01VM2nZoUl({^TB>Sx*P$KJ|F&%P~iv(66!4W8i z0&tu{U)xW+;!-uRQ!DOGC%q%jv;xwY!;Ff{gmde)`W;nDEJW2#jJJprzhz%@5y^&f zZf^9f*vqIzEs?%#&zDIzgs6ozjzJQqByO3POhVKZ*BVM6bVkora{zp^DDUX(U?!B^Bn{s$ z#_e@LclJgx>q;f_NJQdETB|ZRA{U!$J}t!GeAmBE^dao4&}30fq3Ox}3i%7Jz+c|Z zA+l?M(_2x+IF2lw#ADrlB7;%bXGy-Uy@g?ZKZA>f@5 z@#NyklQQu{%3E~^ak2~f>Gw1kX2$M>i0iA;9|wa=>5jnSy$c#gXmxV4a>Fq#$9zN{ zTs@Fw=QbT(iDnPf5pLy`FLxKn1$46ssry0@ZVj$n7!~m^@Ay z{|=V>V)-tnS3}z}s-MCeDeC(wj7!M+TfdR%)!RK_x~QKXLtVDA$z^Nnt7QK(3-$Uu zyoGJir_^p|Ig~p1;-;o$%|)b@%J*rv)O``f*jc8$J;hRSNoHFMr<&B@UN>eV4Xg1N z^fjO74b1K??xfxQtQ3KDR2~e5V^fU)>lt0v_x709~PL zU#mixZg;}gg6X&^kk>uZ$IRkf`SxL2+bEX(cV1`Qj-Bo}pM%9+AX?k|E(_rj|f<*Z;Os>rO8MBa|-D)t4nN^2kZR`-_Nk6OmWnmQ^AYhh(vDvD>?=<~TnPF9} zt(O8p&5V5d`9EZrnEt)W+)>~3f2_-w^KUFa0df-nkQ>JT#UuYJ3;@smTTf&HfW$}H zx~Klpnh)ZHgrbWG0M|gi@y~%qcQS(bBZe?zo0r0c0N{Z9R?l_fu~zj~`Va7n%z~g= zir)G!VqNz{q#B}l70|K#(_Id~H%HnE648nOG7P+$Y1;ztJiWu?g{vzUrBG$CV;$2t zEO%U#!aR=<(W!G^^y3Xc%rp#pWTJPHSZF04e%o6{{m3)jg(NH>${UE6zl62)VDn<6 zB0@ApEIDfZNgCDN=`eEn5*+TGd8rA5l|Ch&#@ag#keI+?1jUlDh9f~K_WG#MJGjPy zqiW{HoN~t(D*Oc(cA%`3-62v3ZkS<2n^mI8ZI%+K1uMNCF@-M+R_)bG=fz8@@#;~L zyFN`bipcb@;-Qm2UG35BGbD2yY}D9`Y=`0xV4rlS@PXFHv=FHR@0M5ps_%itCjUqmn`Rvc7cFrC5_tLg)k%C zUt;`zJnVw{4Ug+qqf=RE%!D<{tVBX8|uNa*Vy9Hy#DP9a{$J6wYCX&j<(T9C{1nAsweJ z7TO>bkV-dl=HV@Ny3_DA?F*xrxd8@T$n;bb_`MF4LExd^dp+{MniK^ma}6XIN<~-K znCldQc@_s`a;P<- z5pIz`a_DI=qJfwR5IvIVxvZgFVCPtS;aOTNFVET9y3swC>{cO}R5U9$aclynGP>F* zm3?RyXC(U;8|P+!tB$N$E_w~|cd1D>-|NJfuf)cOlU8sbac9bh* zb>^?tGARI?n(Yxh`~>CgHHyHL-ubU+>!a%GAvZv$^)J5P|3;twQ%wFjD*pXN9uO5@ z_q+ecsJQ;$qvCDSR-nM~FM05k>G)=dje5E5XhbjhAN_YRoF2sH8lvgBU{w4lEKFP} zSq>&_hC>)|>^c0r*(i|%Y@dGyaIF#JYN%53% z#dq2e4N5oRAd|sb>CocJ@WQXmnrtW8w98C1LYP1ZkwXd=2wu-S2J)6<9QS-=C8SwQ zx++WJJxsh70)1YN6ksH&pk4MVfynWOvuAsfoc3(cYZF(JWW5adg zCfrK)#Z_1uXJsbZk7vgb7W+?B+fBBtE4289${R+t&OT|nvxGNt24pn?v_~mBDk-?NCfrm97ha9SN>SOw5jnbnIo7Df?jBpb>L7C0XY zn6tmq;SuZ0)eT=#P1w{GTk=ak;LG4kZ3mP?6T&KQYQWd|!fmyHj`~0z6p~`*V?atj z?-hWWq&)(R()HE;C_lJUhb`4!b!0(k`3ifuMi!PxU25cK!5*`yxTK>tl|;3ar*%0i ze}^82I#Mt+0j(MWmQd^;U+#z0gc*8eRy^8f1**)oGqmT|W|wf2h9Ky;-@!%2=ho3) z8KPX>OTmj&vWxz93+h96mZQ*$;1dRR2Wx%&!i}!Pk2YP1!W9-Dl$q1IEA19r$jzdR z&?8wbnY^w_2a%ZXL;N$BID7}?@cZtpo6DYMq9NQPUF%2CVpi%Sne8Vud_Y@Z$(q)Rd_4;V0zpXNY~vpWPwp9gRVyZa&K*gT5RD#}moeFu*?N3}&*PXNiK*Sq z^(Es3k2iID63jf_v|TQn10n3K^epd-^QKEI^0>^J-jR&8J#o*z6Ma^gqgLQXH?5w7 znTU09xj4QIr(rE~wrR;`XCyGpep`CQ{^uSjdWXX?LLBszgTNuTlC{)_W?)@uaZ%e2C64IKnf8#Q5&H^ZOhbjCwX^Ty5PR zLGjkSdk&nnEBjA7!GLU7EfoCkLf9+w%o0pu()RATR9VSxzE9DqC)Kq9seW$kUpYU2%_o^gW>~#p8^3YX?vU=+(o9ZTO ziceu;O#NW}KoSr=qb(1t!qgTn^fg8xKFm{*X3uaTbc6B53E#qM&3J3f8MI>Do1aI~ z&XDa!btBdrW_=?$e(KGakwwkwr?_e}k^$bor`K%f`|{>&S6LZ)D2H!-rhVO#!0^+_ z5RGPn$Pq{>FV_= zp`4ZFMoXdWCtGI5ly>uY_`_y8+`+v)#q2m{OZRe+ISn3)h-v|=s0FEZop??{w@eq> zgs(o+4_Lk<;y=l9FBmUeyj0OQkC`zMrZ3C~uw`7X>f=~=_fl9i)}HML0%`);?y`1dWnrbA5LMDBt6 z7%wPMB`-WKd$}~@V+px<;ct0f7D6H~o2N4joy zdL3V%^izMVy+cEB4qLw~DLzFJSPmURWWcWgkG-3P<_p%W_i#|9xK&wbV0D}>9p^Ne zwP-cLIU$Wh8tWbvLs-P|XA74idDAY2Y7c!7$saS+l9C^N){kL`0YoSYKa;Ha0tPQ&y5)Q46YXphJ za^FPHoPSon2HMipAu@kemTw_!TZue(@5e*L1cmaRQekp6Lb^|x4 z-Ze*HN~$YBlRZpwKbfGtS*l&Ke~8y=`Bhe5{_{>-US!7+S{F@UEUfkRe=xO6|GT$C zE6aae(WYmsZ|`VsXl|?je*o4~it?xw0&b#80Hmty|BLUkGS+wg@5OB@TNWr1DBag3 z><=n2ld8h@OY|^A{^vpA!xaQF8#+8nmU55kDpgQ~wPB&?Kh9w;h`ReQn1rPny9FPy z-OfrnMo0#NyVm{8%g-`70U2yr)co{*;WEtH(@G@hD{E^W_k2Z_iClWdCN4wIO-Y;k zEkf>0O4Zv&oPMR~2tuPWWr1ClD`*8MiOC}p(=>~jsD!LuOwvH22c>+j#O@78=Dz{rsRKv7HW-pOzX+=~pUp|Qm12Z+67(Y9f@8CBRH9zy$ zk|n>(V9gj*?8ywG2h#iVP_y;eN-hk#1qT=Q<(B5jDOz7yQ239^5DW_^QZSRO_w>ORr8Ga#GZJsR})Ej z$-l*~Whu2ta9;QYt4etg?VF~+#ZLlj25TKn?iSk24K%}$K_0l0vG3Q7 zZVR0YFkW!(YdB}b$ZX6IxjlI|7+tv~2ST6GOh51O6-PSs&x9;J4TPvLoNmAUS>?QCS=UpphvL2mA6KEN2X$ z->qry-HSfhXRVfSpq)l!8}%IY$5Rj=Kjd%7b+ymv+@ZS2d3v(xK*ZN`M2qLR`Yv6V zc%sB63>{yGz2oLu-zqpZZS}WV3wi>4j}Y{o!0V8CWz!0&4W5&dH`tQUG0MD?t)yU>g3u5X!{0|<(6E}dzkRmPa;yu_1f#~YX=Z})m?Ka*3X-{=I!8-w0@aX#&mZ1kiXH#8# zdqu|$3v&Zgg0V52HIY8Bz;H&rm86{}Quph{fyk8Rp7_S8+S{k7%++r{tfwf0usQnf z!gb%O; zJ{W=Xu$}4*HvbFWLR&DjR{z*Z3%~obqJ-{<8?aKvH5adHrgM=~y2akMSkUf*B-PajYZU8$$ zxkHyW?D@IZdqW@0inaOTms#r>vUV?WBJD$j?s$;flIi1*?Dje}n}_hTBdgplJZTsk z^zXBKNL9&am4Cj;yI1p?$<7Kj_oj%LEwt72T+#k=0|#cUMF+mXBe}2dP5Zjq?y6;> z&pG{BRn|57wkBmSu*|)dq4*LQ9}r&{Z{++!^kN5MFN(nY2Yc_AGZ+a9ReD`x`axmb zWYiCgb_p|pH8DCo_MC#Dz;5X+D$D%G&q3;X$)&3^iX3Fsv8{kajLnU|I`Bk-{?gfd zER{b|R*+FsLnBBpC00s!GET~S&leUZqgSR@y5C>~+=JxJK$Fk`|sw>1(fZXn{0RvKEl zV{6&X!syTiaJg9FRWS)kvrf<@Tsoma(#E*{D;lxN$~Y7oAWWkGVN(5nCQN@_AOBgE z{?TeE*dggbmDwTZZ-rRXh?(6_s|n; zXBR)(;*G)JcJYYBSzSz>|8%FtaP3<`BU4I^mXIDGdEh zS_u;)mBy5gqT?!hn+Ib~RCvrn_5NR~)cn3a7H1k2tj}(YNhvHI$*RrOQO5MUlFBfx zmBM=#JHY4yg+Y8j5(nWwB?(i2n~c%>mT}MUFG=Di2e-0`7YB$EzCgIb3ipu)C`XdB z-DthWp|(>O+~yaaqo5F>o0{6bn-K~*$rvR1Trk3$t>->w)bJ-OEb$7ykK|#Xu{UUU z^!#--2`Zhf$KiD$=SkK9H`kgS3u2VXxnxLG@MDiWV*vkb8`|*fmk9lt<+G>GCoYjZ064Vyd5cJkbSnXa4SkPaEik&Kolyt9mDb?T z_2&Co$NSmFR_noI*#7ghL&rh?xSDN)QuN2`N9-nLd;y)Mnx(X9;4_X=cna>39b?du zs%!bwvT!A%Y0h78HJKO|%^@5}7Obh8V-QWekzH=6SD~^y$k413=n?_^ z1F#EOJI*ak1=sH;va*Q5Oip=XW4?X^jmlqGtRpr&Be&@X+k$itqqLKX=iarFCG74F z+zz^5z^xv6+vkLft3Pb(%&_!6i^!E{Od_sju3KMyJm9O|L*8(&ZpN7)Ydy0de|}M< zC4;fPxxnKE%Jy}J1vD3Cjbd?#1LSCO6-NFgGQQw1Ich#2dNBvJ7et@~$dSwdv^WI- z2W`$W^hBhwQ1f$@G!OFvl>=I^x@$0UIH>`ft-Q?_xMq|}mMbg3Q&OGuIY!Yy-UZn9 z&Qc^0G_A9jOSO*zjs%)Mb~vSxJc9^#m0t~N`y#8^q4RR{qM`>ek1aId$CsiG7HEwg zHjY*Wm>CQIt)SODdZ>GK$YyFY8(1L^mvV~^C~f&C_qpysZOvEft7eHxV`itcz4>KH zGtPQMTHh)PYx9NxxfL|#W`}8j?eKThH3S>Nllec(k+luLQ1?$G!6Y>WnI6K!6# z7G@OVH6sS=F`65u-Mq-eQ`5vDMdo(hoz42#dyH7h&Rh>n!RwS+9mfXec@y7ExVjMi ze)0%d;LP|M7i{!4CbpkUM0n-YQhi`ND72cxJsx}S908AhEv2ySYBQ+0Mwt?if%iwm z?I?;NqR&mPy^&Bl(p+eqzM&A$JYF@RNW)hd&B2g0c`itsMo4Syg!v~JJ9_0=ki917 z24%Ue|C>D+`BIZ6+)6el62|8r(+f~9lS{sWZI|)U1Zv6EW5@&|G^SLkk=QO{Mj}r2 zEEv&d+G((Y=13xP!mfxh9-62*lZ6ol#-WNpZ&&uf!-feaDY>%(M-g-Np1TUi)*spk zNvM}Qs*jglX965@jPLlhsQp>57u$i$$SPu}Jw(uBt)0sz0V2scPL>d^=$2}=71g4# zM@efQ#?Q!e9WQ$vOWNOMSwHR7R01@*NVcV}p0aG$i*PF>QcNP%+MnvkIxO)ku-@;` zT-&_#vGWUXISLrvv;BV=gZDZlc*PEMF{81(t-yej5F6T;QSS$-hZoxIi;R>DXK zObAg@Y^YO_ZdLkhA6kb5J)6jGz>fdOwU6kM96$QQBy}&H{+Rl7zuJFoOp^*kXum7OF0^ME>czIdey`8F>G;6R!hX zdZMRxpS{C0kK>YtNxDVyEnt2~eI=-%#Od_U9i+26f{>m9tIeSQ8D>7BUjOkWM4$vS{cz5IPgU5 zHB*SE+o$q1<)FO-ichs0Nt1M(bQ@~kO_Vm5B``rKdo4{n5s;-EQ~XvsoNiCg4^+$xQ5Vx6*xakPGry6}6y$M7%#4RWEoRAtPH)C-17Ja~7-y&C^%CJfl47YpGUhPWC zx-avYr5>(jr`3aS%`fvoqPpMS4P-~2Z1G4}S59|hO}s7W70su%k5sa=zXOfVHh%+a zFm30m(F0V6#%2J!ugO4XSL?V~9HW4mHOZkL1^Ie-8|gdZdIT@<5qv@|;u%3g?RqD} zP0hp@*yHnc0JmTB`!<&)Gj1(V8Bqq)m5R;~H6Ms^{3Z4G$Dy#|pK#gCf<~6`5ucRO z+vaYB^EU{bJVDPLvz^(!sMazcQ7CLmkQ7x4Z_;hB`81htL;O|r-`V+-9-lENKAsEK zj|9iMRSC6P_O*uYF!@|x^nu{@`vE8TW5bzfL2OzDhh{pTPF5Iy~&rjycAh zpR!Oyikm&7z+Hrh`wXD6BT?$h4|l|WjcN6K|A}Q9`SOkmgje&sb(YLAaNq~Xk!Sqe zVQiq@EahVKy9A-ys0;0aFH^lq3>xvhDJGS~#xFA}Wz_?OS}fd-!C+eg>ec9SfvhfJ zJk$Jwo^PtvTCHS)*Fi((k{m?)G*lJ&B&a2;R@9C*{1XT+|JzTN_gI60i=e> zH~E@@^Zhmk{w0t%MDa{`#A}No@Vwjlo94#|B)ACEK{cVipa4BVj`ueP{@r$=bw7koRv{gt2$FFH!;&uuM8>&z`Nb9H<&XnBn!Wq2U zaZbFY&tl|@-C#o0ZUc(xq=k|zTD<`Eh_wSeZTi|y8&+N6QdLmorE?tCvEe~{3(6!g z2i1Jz@a}1@(JfwIXjE&|)e#A(B7R#_5yFpzEYD4Fi zQTf34s5v)mtdgz01CquWe3()l$j6$l)l#^OoL;jLuh-9G|L?uO+M3AP*O}etlGFPh zNHqX6)O^KYR1;4{<`V6;V^=H+yqy;lkvYn}!~_i#$_^leeBLVy^2*&V9=L^=xu?NH z6NuJtFPziAUBmdjn`Rb>*sgr9*MI}cCa1C#<8hz*O~g)mZV4&v@eWKYb2PVqJP`## z=01asze4=8Ds3Psg{6W30Z9WA1^)&@@1Io3$-&XaTF=(r#?~0noHqVzNSCDCXR*PL z&~;9YmPI1}2n?Q7Si}=7n57$uSnr(lBgrMmSqFhoUNA2N&0U&rAQ4M&zObkEPr-Dw zkyO2L32J4X^LA&N8&g4LqCBMucXoq<@(kbMkQ3Urx1Xt}97B&-e@4iT2;`hv@7sAjI8ql1HJxV5b1(GRa%>iQPJE(c6%`|ZNHHcz2m z1jcpc@MMW)1GZ7)MPD|svPtmqzGa+Mj}QEb+Mg0>O6m}L_fsj)`pTqMZex0r0kY&^ zOeeg1$=V7(fGKV>xn~#c@dYw6a=|7RKz}yCDbDe|Zk(usvjxoFpl=K_nJCqz5SIkJ@OrpFK&=0E zvH!Qf;=iwF0KDr>>N^1J7=rhTUfrgYEWoSho*U2HYE2P1%N}G987t=zJ(}ex-abnV zid13^&5|mJ|0Yi%^RC%S#$cDQ`Uk!6tF)nD=})XGIcd=k*!Cs1or~#7Z>|cBbQ@FtiDhsj;h-7MBm~oa@b({ohqHIQBfcTt+Tkg?eCRLRZ5INL)r(Ms3DZsdlmd zA8YRzTnV>r4ac_Cv2As1r(@gd*tXNLZ95&?wrzH7zWX`%p8MYOe1Fb)>r2(DO4a_g z_Fi+2vE~|c%wr4H^$;hF!9+0Z8~cqK2)Gdqk>fm&f$hvWXG}?n<1|ksx&S*d-f*$2<}^4%0Z)!&69I0n}ZmH4P~Vs9nw74VaOjh75o z>~(Mks^KmRwVw;%f2(vzSK+x}fEmR)H$>dukENV?`U6en1AI5X*TF+QHD*hL6Rav;sBmVkQ))N-pLWQ01P*)&4uUJ$adhr8bbvRMYk3Gf*$vQ zY;cEdh*z~|?c6@jcLX>d&X=Ms2`%7YlIAIsQ1Pr-{u1@Q_K>s9Q@kIiYiD4Yp$-`ymfUJM_hjsH`8U}Ol z0#r~(*qDu=l0-h$9#vFr)FA@}niM{|`s$U5e-aQ8`>sty<(p(BPu3zkFG?r#T5}K{; z%e0WNLH&7?XCuTr^KfadKE9dPtL1FNjQglI)T@1mFQ$}9@#sGx zWV1Y^fOoi6Qt9`N8MfFxzM9w6K#M1oC7yy07u(EemX7j+U*<&aN4eVj^-I&pl zRokfB`tznH*o6-_hkCsOUdE|4wuj5n?LbdKIaaRB$yBZ`A_2DDr6qL3fgs0OZs*|H zE{T>b>4y5=~JUn{VoIY+dCNL<2A;S`eWM%@;GGR?5!K zv2b+20>oLxKd2_vEGl=()t0ZdCIgP1;(s*CUlb@7WzBQp(O(oSY+dr<^`9=3+OHT= zp}z9-OD*!%ChgqWmy9}8o$$Cg=e5fu8x_0Bp)ecW3^E)z&v-vTSpUjF4 zKCj^U%u+@t>EZn-yYoj{HR^O#!wrXHY;XUfnWKoQpxS{ zdw}(eO$jD6kwJo5xN)=8|2{n1%c&R46d+;91iTE${=cEKp3&dAsh)+Ci46d>0rO%1 zBB)*GRR18TKoCjy6v4Ved2$ToP#T&g(uF#CI+!w0iHaw6!;f>)IfRKJAt9tSgxv~e z;`NQM_7@9~tGeEIlM~I`m5r1lVhhw}?}@dvn8C!;&toL>DstPR!QwGos2lYdIG9u_ zBk;6&utQYgq|o-fl^9~NuwwHAKzm>5b5AUBGs>@b5_7Sp?$oM@AvcQDal!6H4w{r= zCL?H*eWZ#CP>XZ$4~}8nm4UkY6B*&K$~OaX)!iu+hS8eyhF#Ax@I|N{QTC|9lHB!i9pg_Z!3x8yapcf7xS7?T)99p!J)}Z$vgP6 z)=mq~&~Fb{=*OgQ4ewx=Zy_0+vEMe1kh><1(C{E6DS;nxLMe5AR(#+t zc(s1!tIRZUC~7ACL}i|Vf5dd%SSy|DH$OrsKJ9|sXn#Y%WpAJ{NhFm4CX|A|l9%W+ zWCN`&2~`qLO*mkjQog2^B6}Dij!2?Z^^dWmVd_Z`3I9>U8D9*W!sEVXbiqkah;!I5 zaOP2}yWCxsC+y-Jasb;GOf17puQFg1@$d{U&KvntOKv&H8GJI}SGp!|_d@9wZz7B+ zR@~jYA=oj4qs?Ub&}_6lK^S+p-DH=b8hM>(V&S?0E^mW|;dz9Bw-Q^`m(LAO1YC{Qcbl`HnYq}aXB;d0Qi+?%0cUXC%)>-6 z#m;YH{7ucqHU+fw_Mz9h5w)0gXP>=eV%K|eHx=PaeJD$)Gaj(uVl6B43gbWmw>RHk zsWHQAtuO>kN}JfhW=xwgo6YnEK(3rQP4r1*Avl+J)IhZQz$HqQ(jduhS!958)aABM z2VN!j4Ja97r>XO11Z8*{ZqsM`?X7lENuj1XJ&rLxb2iCZ{y9-H6KvnEX8!a$Vx}eE zZOhO+37mXcA7(AmJ`YH2INv@Ks>~YUu*)mZKemk2=@;tq-)Jv0hIHn4NuCzAArHYD+D7n3zrR*PBS`!AK2@ zB6jmZb2jW=$dKJNQK(jO3n;_FSuSS48c)kBh*u?EJ>cnFZVh6gfN>_0F*yOyyd3%Y z;P8}5@`;wvRi`^{!FXS0qR3pLdg|XYU2ITY_Wo9ENU%muOakn(8?gQj51Id6Z20HB zOV7d9`X4`b^!Q(!6n%P$AgaJvKtw`A6Q)wf^sW@HMWrH@9VHF$wT<6eoZw2q{*wi+ zT@XC@a|#m4!ZfNgnmC}H7|n&{GIZs8AUe1&Wzy>e;o;-S8m6{i#VS1wLuE#`5lx09 zoDn;FdhLk32uynp#H<-IG_M)>WU1hollEA|%n446n#B1h>9A3l&txTZv=Sz7^cOdcS``#1VH{`YQ8Ev)~mobrFsDhE(b0iac3D846iXAq&WRaV4UeC!f9 zDvZmw3J@2?B3Dx6wL*|A4lvfIbKn)aB*sagJrv!#4J+;mE5$B0H4VhMLb;p zZFj;rP-9}dJ-j%2wilgP61IJK*k>dygE{mu%etW7@#3zhf@{tb!9pWpWM9w{elszU zY=>&|8)XP4kZsQ+hOAqEJgZI5MLuUI$4QzsmaOpfWl}Y-@O)#ZsYOAL>^w|W4O5Fp zCqC~}?>vE=Xx*=6aXuptYLtTM1BNDLinGj7&*H9;q>cncOAF=~(&iRLy+h5P2Vz;H z-^m%$()-_{H3R-=XN{o0SEY6M_t3C~{=s!;u$3llHRQIgJRoqFg$f4Fg8?P=Ft!B# zRrOxgrPQSbL^KZS)&mikCEhwDHBNsWP%C{6vO^|HM5>&;4C^gKfm?}Gmz|ph-by$l zqyt24ZJd=Ye5wVcg^VC#O=JrCMAK@rGACIV5)jrK6^%Y1$nLymDX3GbR8Yz8MA1R| zK@qGnO5G(>Xc9RJ!f&rFIik)?O#^^ zK|xF?-a;CJnJ7$`&MHh@>jnDcUOlbJr#h)3u4VhpvVi-SrqA;$oZAeHYI!qC@ir6g z$&N=h!#kxDD1}^pDn(zY<0OwSDFV>Iz$sr4a=CorWoTFJcAMasEW3+1v6Lyh7?uVv zqlkmbXr7{DLD>$ArE ziX(VQeU;qLD9n5u7y^zh2}bkUQXx63GK~sA;y^5Ta0s%=~dU`n!20=7`s?a?#`Jc^j^IbF~atyFDiL5xvn(Bch`_e zp6bJLIlb)IvepDQRMYL02P*l##z5>=pgAT1zR1~E`QZrFU-SKxFu~`c7997C5dj#& zZf74UVRN4#|C*PJK!X>&0a+>+u>OtCh5t|N>ireL{{u`>y?|T=7XnDgwev7%pinR{ z>sTj~o>b{ld7EN$FkPJ%ABaR>!zpgMsB?-aA&pg;_A}prvS-707NMhw;umh7e=bNL z={Qax|6rMF29{rOM{g55dNZ-4Bz;m{+KJ@RtQcN;6q?1|$Wb`|l7v^H?@(R}>K`5y zg7Ep*eOdMAXMO`rOi=>7eE)})umARo{j18`q`qmn|Bq2jaBbn>n!J93Ce5pj@I@9x za(P%JXjYjjG}1yW^r=NNg`KA=xoVx4sBS6gA=a*MFmt#M6Xv9o=3>9=e^78fPH+LH z6dz?OsEYm;bIKS#g^yTvSN*~IcA3$zb066-&oIrv=QNO=PsnSVCCW*(Mv%NdJ5ik;5^)LI%!c=<+Igw3pW7po_qDYkHsw3QE44Hg1zm#+Ns6AJdBU(yCQj5n7)Zst~MM z#2Ej$_lx?bs%vQ*9e>Ys#u`PWC_=;s} z??=s~jxiMmn+tN#0BxdgqHo{DiZ|CE@Ti4i^b}!ia?|!RwDiZI!psPv0s>Uype#V2rT>u~HyyR*y zJWb5tt2_aHB5Y}uF5%w|TWJ_kv1Qi#(S@@qfmH(6uR)&vNRUVKihzLmxeVT%x8pZ5 z9luE9F7KLqkn7zzlUz3h-=%6an8z4l2xAB^b`nkA4;Zq`{ei}CiZ|E$hCLs4k9 z@rTWmRiEz6_FPnc>Ht-qLEFHF{p?(rM2?fwq3~6~i_ogN33w2=4I{W7v_@Coc`RT^ zLKu}Uq=JMnB}9Bx>521C1pku|aU3-stliSf75ifx#NoC*wjg`HzEsR3F1dnHD5IF7 zUDz~x!k8hMehrB7=;G8M!{Rg^vIUZ!Dwpl?I*Ny*@hE-#Pm3kU zqCC#Ix(TY8ypu%#EEr(UwMEmSVnI$EzgPo9)~n;3_ERJrT%^Ly@&3ozcR?P)FIF zl^Ll-AJtwf4cqLyOoGbiuSw*<6&!!zSP^`m194s{Z9MoUSg@R6+X(6?&dzI!grC7u z-nfc6Segj2Bn4tFdCgkIRtyc$_FTMr!eQzz@k1O{oFRZ|-Nh44C;JdAggqATsOeDU8{gGx}AiZ$n6wpj)!rIma=z^jq{5R9J;^ z-M0EtxbWJf>swde^Q*H&`o>YuL<)jS@oS*00&0V-x%GN4dESR#bD?MD-ZaNW7uTQt z`Yg~Vf?xZbb0k_w8~S74rFtH;!HD1UQndoy%T}>Masn@fhR8uz==V5QsQQmx7WVB2 zKuDF_fR>Z>T@c0d@&iwl4E3Ync4^b|Y8q%~nZZ#0IA+g=J^bzN<6@-VkOlyeLBJ9M zEIR`ub0Y&i13L>nz_Z!UfBeIu$EasyZDI1$iQ#_($v+dW9^eBDC-?tBljvTUKt?2y ztCxtu1fg|A%Ep-`0p3RNf@377CgA9JS(s1n1kREyj{Xb%6zrL2?E4P-C16Ajqsk04 zV z8tFeq8V3_cJHR}Lzi57v+IY-5JKE+s4U~-`Xg#Lr`XCVX9ywjT1;)1$9V}3Pl35lJ z6G@~~!kRx|z zRxp%TyqY|;dFXxVb_y=4IBR@RVC=kNRyUvUY3$pK{hIlh5%;{kC)+keN%8G5Lu0`Vd8HO12Q8k5XBii>F^lBekAXBdIR!V{zdPxu;1)iOW1ngW>2+KzB%2}RD2nFHpRjnx z8Ml)m*8*{XTz0Q$p0|Xlw4>@?P_dQJuAi$v3qJq+fXyH5@b}>s;%%7O@ma?y|DHz! z5!*I`E|XM&OEnyJOg-CwE!zukU8u#|WrjIrpqk#X4H25S3DGM_Y!o$LN_iKMnAztf z3?2Of)8n6dCe)ADi<+*0?-Qvc2GTghG(E0E$y!Vu%qWXIO+u8$7++mt{-_dqbM%5u zoX74;>%IiHz}fQ9wlB?4Mq%rAYp$)fwP;QeUNjTd?zTFEp)Ao>`rDt*oaC|cXdbJ@ z=8&0yc`hcC*ZZhvvN?EVOhj}l>Eje$Q$DAu!s(9;z6s^{18%EqgKYEd71iYGhw410 zr_136BW1l$DzJc*kOCfrKmD(MPBito6CvhQk0K{5v!^QZRnNoahIxz~ESBhGgQBX{ zY-EilqvzlNK{~6B;WgD4tTVCk9b4RfMqS z*-V~A^++YG_&u;T&Fmg!IwLd0v0gK4N@U*3I>yb2O=FL7JQ@7}bX2ouu(3@GS5ixK zg)eUjmTzoQYHkE4Sc#fNYCXbZM-z=s>*aWgi~I9)@lEW7`f`fW6?6q%S`c#5Hg<7ohq(n=7E{c9K_f_|R+velBWb5c7Z`5`= z3#LniWSQZ@*~9Hx1`E$Rb$f{jwRKvQojxw$v=?*0volVw1&T|hSxfFuZ z9;D%frc-j0WIEJ`6PIC@qGH5KOV8Z$;`ZOu%RD!itePRM$vA6qa8Irwa&QC|HmQ{f|FVm<;gRR{8aEX;EH zFGJfRwathFfG}%X39WS%jJa0@$s+86I||SP0=rHlF&`vT;z38A6{OrWLmTiNMz`ez zHY{Jh7A_{H;`HI_`iA z*=P>&T=pctrxOZ+ub0F7b?>P-a9hq52WNc7$17cm@f7gGjzL>IEuiRe_+eJ(~t;+tK{L14REcN8VRL%w$lK9&Apf=~{JH}9?-Y7NIw3pGp zt^x_U)|qA2y+4tm?-rC_Sd_ms^_Fdae6;y!beGwlbsLO!cURYB5O^%A#Ia-owA8Bh zML7bGZSGrRi)zhfC0cORB=RUsiF%w%43lcP&oGNAldd593^QGp$mD);Pdhgh;#Zw- zOFG@nv)k1a>g`Az7+5JC2jspG3Cj=gU+dZnYLno%m-!?E@Oej8wcv8B+b&C8h%@W& z*Cwn@+_QV@J6@X`yeHe(N7>G~b0Hi^xH$ zGYpvw+)#x@$?YmeekwE@H<9c29N@qIxLxo5MlUmla$IH>ssu$HA>E@1bG@2^(Q2o4 z`#Dd(tU30HPdE8sCPqllAnr;|&B`d>E(PX)nIT$CCyr#%eS#t^&^4A};F1?09H9PM z1)oQ&O?3${CI}8GiTe`xp;98cR4(e@9K{cr#&{ouZRDyi9=!T{3_a@cBs(>lJ=I&c z(EI7oNOOEz1p<6xxMR=@n^3c=@*U-yrv2mBFLxBl`^PD2)+>h+WtrvIMe$|net--t z*`v$W6M`FBl7IUaZ6sVX-t0|Ed}p}O zaFIlDG>v4fCTC0Q6aUmRo3XNOSLS8hs@eA#@g<1$c<)zP3*imiK2q|>|pPjiwx zV72rX?1~TBy#uV~Cf%ZQ%dGoqTML*uuB};vS~RB+xnjG#{sRin?4ch!&to$T@a_d&}rXz@107UnL)s$`T{ci&L@q`brJOIJ{tH}RvIPU##qWf1C)w2Rv zkOK%G+tgp|77kFv&mneGTzLcvgx|mjk>L%y(2NkHvN|`fnC|{vpBaCJNSdI-8mqx3 z@u5=*3CC+>{iBbo1zNn*E+>W6=(2;iu!WNa%9-IDhdvfwsEihx-6ScjG1k}9Xq{qx z`e-Kdfl~W7l>L7Pbxmau3+KG|kwwio_(%q{_$y-3SA< z!u14=J-9<_OG~^XN@OH@CQ77|FiKMW30SSAFp2t{eB$XfwJeQ*zx zaIT`VbZwx2W$(IjU_|BsSs*w-CB+KZ+kbFvaWV%CLi_8dECOf&HyHoY0z%|i+kF7T z(o5#?9x0Zjm@sKdPepi;8Ck%RgGo`{uUPSugklIu&+A=(Dv)ZlCmY$$De84(yWbs6 z;#!Q0SqnC??W^_tZZb#9ykifktUCR^F<>{EwgZ&}5t?Lq04!!c$_Y+O)O^!{I6){a zMzaU}r@24|Wit~$F9p+9&#btt5GD_9E-;pHBmis4a99$jqc7exBg7Cz1S+qg&M&`D zvCmI~a7G>p?9sbA&$?4d`O*H45hO3m(E@k4r$ti~_N2>syPaV3>Z9cH=T~d{xsOZp z>(j?4iIZ>J+vW1-d0fGYe$p2t@`iDzWRmLz1Dm zQ7SCuKB)ASBgIR{5v^~(`=gf5GqAPmE1*>uV5Ce-VzNuyy0GgjS@YAt=r>03im}xg zK*c}`B&46p5&J*B1q*9sha;^EsO$z9pAO6AmY(MlLcGmEK28f@_&pU>Pe- za9b=NK{u@1trQ|Tj{qb1xWFQaM%Cm{(tXVuOUX9?cy)pM_dI9*nTJeFZ5>SX z{vq-E=e-+ngqu`1BLJ>^UCT;%P7N5P9zcP@^{4F6vdJ?Zu!C4kzr`~0>PcDm{h))% zi4ukKIJ^V+df9D8;&UcxqP8f_#7NwYM|Euo+mPn|Ds)a=$!HtXAZ2709rviZt3suI zzCV+8czzvRJ|W6oz1UG~J~M6}+*2q%+a=f2I%levArryqT8XlnQi1moEu0%P%>Zaa zx=3>FCr7NHpSC%Phs*2!s517UGABah`o<8#j?ulUh6pM??UInOMU`*m7v6AMU*V&{ zft(Hj#wvF-`6W|yLjXRi9D%~rDA!?i=w9767o}dJFUaL*C=D%$ zJM^LS3qsS@@23MR&bQq>#kSa-vF!tN&2}if$uk7*9!4BC=?B^deZyisaTV^Eqr2ASplU;_)M(%| zgYu0)a-HFN_7L8sjj{B|B_sv4_$3mB0Wiy0(uqjgl3;x-lCTxUiJ3Nfw;}_z?I}nse=h z%hO=9?#B`Eb3AXhrp0xYE#NAQ8?$d5+VdEfEti@c=)^4vzN7_ZNwfV(IEN~iS5x|zFdwrjU!JzsfNL8?+l$bp2XE}uC1!?WRp z6SPbXN9a7?yYvVs|H(q?%C?W$>L<+z$nj2oH9?H0AS4BMF$cqTumsaMS}3MTJ)4(c zIi<;YXl?4tpY4yIy$6Q8n#Gr2Z{lCgvv2-HwH`ufKHKQ2$O2Vj zp5e@PPJ-%pq;{egsyYUZIBAdj9fVqFWW@gt=X}i0z8(0dUn#!wRDIX#dr9hkRh|{C zzIIca4Rpz>55w9Cr3Wg3avoC0=DjdOJ?*Io6j}OrsT$;CmVX7dsu_zzB>=E-0f3F+ z-v>5lCnwvVfP|2wEc+`1fN5`P>X`!h??9yGn^J%5873c5s$xM+m#ORGY|8UhzC6t! zP$tCd=@jb+?v6UsIQDHSxg7bOq`DoPFQXpb6%eWT;j-R|tjBVinA7VZ?E5^=>1#FF zrKIWc7*0Fz5M5%U<88hHoj!@AnGn*~%p8|o=^;{{6`Ec2L`oCcJB2CwFn3l*o=9JH z&MNd_d8$XKRoTV-y2-S6%csom{sp8|vL(%ty}y5GJ8g7q!<_T*`;dvvyO3HD;U)#> z2Q0%+k{>ZTEsjyO;cUklc;>%wOfk29G3Hk%LHe1GPo>Lg*5nfCR*Vq{X!RKloF`J(I3u;K^^I_N22>}o;oi2mYYMAoo%66fIIGvnm8YX8 ze$~Ygj1tNG|Ra-Qk*2=!BR%>p7`6kEV~x7LFqc(iO4dJ{!EWU zda1fKB%~&|S8}L??v5HxlygyCx3>Du+AA{uDxY9z#WC=tJXgz$Pt#c3V((%)6qAEl zFUy`}K)Y6Q%^VHGw27oU6(rQhF%cQoq1ZnA2eN~n&`;OE?}yzY>*IJYlEvDv=M;LNN(bz0(5n()?z`^=5Kjy$hukx|Du7W9qV-dpM-Ox|e1M`qtG(YtI&Jg@q)aixiIDaUPgEGdq&7 zJ9+OR>52)-Fow zX;7Q0HL>NH(rb79wIkmNgQV(swO{t<%}Mq4J4^t!>kB4jX75vj8+eS`&Rr}klafAq z-#`$r>6_Yk;i<;G4K?;wJ}F4v&~ zx_+I@Zg8~@NZo4yYl58o5u!sZ?UDn6hL}rVofI=Fs!>5UQwe4K%Oo1LNb|rNFWr`u zCpE3yQ6FB4{FU`Bx+M$9b9zg>kLBK$ zs(PK)o;rNcuocjFDf8DZtzFl%bUoWSPA>0Vs~=pev9jcj1(B(ps7&2iBQAJftM_^P z(+?;2xoC@ydyC}u%|;R3y2>`DNTk`+~)i5DaJRh6QM#;J7tTN!qVP}YcRMD}*f|~PuTOZ=Q{#~2Y%-_O|W8*5G z|7<5=zAAE3z#?mN=UrdS(&w~yCsn~ZKdCGNNeg}VSTItgb0);JOckChE=p_#ggJ_? zO)IHtr8G-}{&<*}1VdS72u|7ed%pz^>>`Z~F^~&B4Yogv^D-4)P<{9f!E$6dzWBU- z;vFi34f+PO z1Gm*@z}i=a3#fpRtXhQ5xl~#W8MsJ&_H6iF%Sf?uv0w2D9VD&3ROKhIkQ9&QAvE3Z zc?#L=EW=^v#m_T8bBKN|eHx8& zNcC)C5EF}5{PMM$yR!rgSdA&ZsS2DBzV~9WDfNju$-=q?hfe31WRwHpLuh{Z1FM2* zs!E!6@WkXy{czKt1M`#90;VSQ)_^z{xltQZUNV?D$HW>WWi12Y)*6q=8^;#<(N>ajxDD4O{_|G zZ%R9j$7t5mREkt2-zj#cIt`nvG_jUgCB7%ybUNqu?R})ofRN*3zG370mcEZ2h3S<= zfZ&p+6TGiEbyr92e_*3I()Z1#%NpYVRcVRosJA2S_O}X$#SJB)%A{B3X4*(}hqE(@SrqIJrV6IG;ombXEKP zt*Wjnf#J_8i0)J`-;*Q9HJPFI4)E>BqKQ00R@E<|CWQQya09&Oi4eXYwm92sG}s`} zZjk)L;g5fN`P}HhBNG8Itv!I;)g*f`4`A6$m&* zXY8>Kk?fuftU!HCwaNxtl8Q|_Pe*E7>J-`|_|Kfc%H|Q=t*l2-%)$GL21OCbzWGtc zRmKZ*wzPs@HI1$=2m>_{TV{$g*nXQ~P1t=$D>zbB(b^GJ#$7zHLTsDc8U#eF|&m`jjZ+^vF3x-s$h>u*O^pFm0uAkZxYvu2+s=cdJ4y zi$i}#k>LI3nDKf=iMH$*n`gW%t22I?+FV|@4ju!iPn$;PK|0QBXON}p9d*5!>RH{* zZxEhr(N5Yn^bz(YW3^dzr6y?%+TCQMsZ5Do9}hp(+*Fg;((r>Mx^f6nHQOZcR27z{ zF5r2BkFoFy${1JW4_HAi-69x8DH;@CAL<_TZXY6l{cT-6x~|5bWl zN?Gu`aEY|1{Gq8ca>%PU0WIO_FRx0k75fTrbEz8Z{qf@bt+Y7<&vDD9?ZQl&V^Onk z_6~N(z3E@yXPn;}` zU=A-)Cv`#dL@Fp(v=D^yUx0^YfA5D40_+8xbY>I7*BQqecV9xGsz&43!vR6x}yrVBXvYKq#;MqhsrgU7>A1Uw&<$@X`zbS z-gIhJBK+cE;VAvK%PpMsJ4@7z*G2NIJS?}*)I>S@%B&_gUGS-Ihp~9AGfcC?)M~pe zB3XSx%5r5vOUuJ;v7vD>H9e_mEFO-vB5bI@J60&|{!!$721<^mrnj$!{s?qB*#rlz z607v=#o2HxT?jXfeukTpxoAP49i{QPy>ZhwhK|e$<`;hM&$q@NHCWrBM+gHqmbu^j z-ukc~*y;nM@RDa*(&a&UZ7&~0K{~p0`UTUU1x4w#<*e(~3R*_Ywne5hoxP4*(M?fy zRg6aYYy+0Z$wv6*_|sTv3Qm6D$eh23ZH`I&;1>1gvjuvs_}J%v^}1{y9O1Tj7n-g8 zxUu4IkHVpD=?7I_zzT1ocz#>W44y=o2|b8qq&7tI;C~3Jv#tWP>Dr#r$z^{1>s?3& zKDjjma0i+KEWv;OF7z*v`nL{&zm)NCkk^36g^Nc2SD=7^HX`BW{>)=Vo$`L4C?BY< zPMZ{^+x;97^#UO0AB<(I>WH!z&_wd1S%C=(VrvH5*@)fPfAs|%m(%&HKNy(n z1Ns7Z0et~hNcoWS9<=Ur>!4dGFr{YEQG+?{G-s%4wK}(X+ zz{qLxJlFD5OXI*qjx6GUC%x<67f?a-#KPKZFwr2vQVzVoi2Kv0OdD^mkH~^S3GyeL zviV!kWn(DRzJQeZe#F^tn|W`{U9YwuG8p!b3b?$A)-oh5&K#&Eh_CHFGbt4{9%WY# zA7?^eU@%_u9Iro}5ng}k&aH31nmWgP;oqZIPF({SmC-YdFURw3FR3o^5gb8{8fLET z1A{m0YfNg&b8V$(Q~A*AjO9c%cLPN!%BkE8VML3NHqx5~xneR^42jTyFk3P;iDzom z5xpnRuH`j#7@4C1Mv#>8OOG+9s5=^Z;d@D%xmp$urVMDc6`jMlB$xvU_BOY0Vyy7G0wma)d?Bv|%rs)>Ik}p?WuipZ$#< z)5mR~LS##aYtONPI#&{y|B1$rZ~DFNg4YoDhrF{JtZ;KdluQQh_5|&dF8SfZ9BxpK z2K}-)%Tc_`CT9{^lY7J9HvSD~w9(a@xQzYaQJ1_sJz*iDgj~{$^e;;uS^l97$pkIF z-amaQgu1m|yCvL^#1@seX)vW!MI1DFH96V&lQA=2X+&t@Ff#?43ra+L;xI%Y&+K`X z-TxXfu(I7)u7HT~21Lw%kSqRI#QalrrpL_4^k2j?5U-I22teswgZ>H~ zo9Z7zND*|~;oR|Yi2+=f-L6fl)?D@uReF0PEDhfqDl{uV>vU)iNRUHSEu`7IyQ)rZ z?<`*)#$T1hE=^M6WS4JqWXui(VaN(fU06-4*eO&8t%$e`LVoa+eDuQAV|0{(5Pm+z zyCZa71HaaO)~&VVhpbbgJTx|oitOBU1eUuQ-QI?;qIyDKDWKU%*q`x-bJ&YLo>5j1 z>sn6Hy5?SOG{RVR_`cE0`P*|e{a~NKVuroa3fsr>z49k}6d#xMz08i#5JQQwiR5Fx zuu6$pI0@2>twb^(IYHJfonZYgcc z6Vi(=qvq+aWy;CKbVwe}e-p-K48DN`t8mTn#zo_zl*3yz~>6}F= z{jp^TK8KZoVr~6FTU)dHOpthlIX39bcWnjZ^Par{-+&n8dp8xu(TEHoj;}4J*XP|@ zcf@s8*!!pCK2FQv#b5Ej1dI?CWKSJh^(=qL`GwBTHSc$8epVcRCD(26{4lo_S>R2V zB5=K^hdT7qTU%rqx4_r1a9N>AZS&onXHj}&5Rl+NRc`*@PBlB@^2#KDtJ(v&>c8*K z^54_8O^hv^{?Uiv_|N9oBvl>2kSQdeV=4>}V&G&*q+DW)Ss?e(gc;0!LUa2hlp=`$ zZS)_3An`f{bcU=Hl<6dta@yZx==2Pp#6C4K0fv+H4ueifqgR0&^+$zBlu4ML?v%$0#G*f-a;86S^#vU9M>(yjZo2~RJ4A8D zTCU{+goIGW1AM)~NS=VU1s(%L?uCgomXu{4dshoiN6;xwnV~5PY#p&FUv#jj*xkww z3=hV{HK&;t-Rt}0P(v^%6S9>7rr=@mg=Ysh~Pf&JzR3iKGAvM*Pv;11Gyf3k%{<}UuOX){iK$`)XPQj1bgJJ+2qT5 z@}cKI0BhZs(u#JSmK1a719V#XDZd>Eb&&Mbb%=MWEXSlB_~_LSJ++6{Iam1B;>|z0 z1>a@2(PyV;!cauH+@`q*Q_fwwe;9e?esf)JT`!Q%9{VZH{6N)IPE~uKu||-C6~OqGtQN)*>EuU!)&T}I|Ioh(wvomWU&P?w0ctqxVQ`Yb8tsXlZy%8@ zmH5E$ulUD+(xL4Rz`siX{_*^$jPbu;y#GlWvy^rI8~W7WjRVgKknCEmB={-egI{6D z!17ics4b<36k(29zP6HRhaL6~)?UfNJHCHs`7X6M3gNWvU=Oy{SU(^8_1s2u{ww3* zSbiN5nkRzKzr%Lbb&c$rv;|G@M;d#%bIDM3yoxqsE=(9NMSri5$)JXgNAP2Fpp4Q% z-&B$Ox^2b=oQe!2aLv(%D)7$!D~?9JW|8P{scE5s)a*W3=v+D!DW1QUWG^$*5nB1=PAi%HtC>%*vW zJ8V_|hqQO#&a_*zMq}Hk*s9pJZ5tKawr$&X#b(8}Z96%6ckk}6_j@pQ_j$&6{=s!$ zYp%H_^cI;+%lo*Y>YZ0`HIlUqnXAOtMw6Y=iQviI@?0cboGXg^b@>NCmsUJ9sFL}F zp=sKA7;$cTfCmGT2Qr1i7nEUaHg)iIC_3@EYqAwt;H}lfV72V>m{36*0u;ax{Sjmp zJ!KiME#~6Nh-?xJlvd|J$+C6PPG=Q0^GAUrgk|?QwWnz7YAlJzl2CsoO%+KYv`;Iq zb+%n4#7Cbfl6Ac9ECj%s^xw;>XRDfA4(kca8-o1#SUq?HQBtLL*IznCe5-k5W=S#m zb~kB^G{=xijx_#eurkKZVkQezoq~kxLTWp#wG(TpoJb6@{(7Q)Y>)_Bm z0{BIW0LY5?y-bOg?#AEb#?zRBbwrHwR*Z)p9*%lkQ@hn_iraM@j2(8h9YU-(*MAe2 z4Tg1oAqqrGIZR*)Sn2|))dPXFB+!MZGFtav)w*06R$wnfz86108U{W)PpUxKjMqr< zXmzs>q&gQ6H}>HpS}o$wqC^hRiF;WOcSNFv8r6y#aYoSwkv}) zk#c)7M2B4)oAcbD2q`z~89~QUv16`u#qK0dT zG^0}+F5N(W#y(3uzgoix^?ZalxwkdLE~N%+554}pOo3jRiX(&lM1pYB3&wWF2RUP? zjYUM5qQNANW01uOjdVlDWw(qGW+Ge> z60@o43-n1!0cFmnS_9RhEh%&X_}dJ8(r=k0FDhUd7hJ#JpSzC1@zJH?(k?j2P=oN| zTv$jnG|CTlV~(JK!coB4qA0Qn0|gJE)R;FDb$P&K(5`GkTB;{A3wvM8)p0jzJH}Pb zjkHjmz6v!17fvb3{)~@BD4bOuT5F#8;sL+Ku&h~HnIe>=XoZi0q{)P&{Gz@ZAHJA) zgk9ZC#M{}@UE9(-5qzob6sEmq&?0m67vVe+(IL_iB8{GAlPQ}!tq*kZ_$)Ct!-a~`cc0S#Ji6PgeFfd$e&<&wv3Bb*k$W=4uQ8<~zJWwYXvbXA$Sf<9m zqi2c!^8`T$%vI8FD{ycu9)Oo0z;%S#gDk$H15qt27q@a1RmG}@Qf&V~XmN6Sb?1Vg z%Jyoo)Hu+TMmM0u00F+_1f!WC)A@+0*w@+UCKmu1K4>9oTW6OJ=z|ZDv?uu104xGjH!!5$-Ai2wkKs8EA%RV1WLGTiI=U9?aq#%pMt z`)-ACsfmBSdTm=!6*_hK<#!+%ykjm?0XeCigjwoOI#w+v9Kw7m<8&<^&wdc)3HhbWeUpsn7y~IXQCx^8f-;ar%C#%WiY1T9PXcsm0|}oBU2?36@HW zMAAXa^v$~Vkl;9&t0Vd|OZWv%!S*oj`4g?&7b)d8oYc9)Uy2i#W6yxUHyGQ}?ae|q zal!^D-t?`}C;>OwbV85Q9yMf)OA&tDrvETEqk9JkCcS?(1Y>*W{7R=yQS!R45CpM+c;kMd+P}P8? zUe%>+NEsDwqr!F8y0Uo_O_ZW|Y&CJH++E}!W==kTuF%NapAq{P;ui9<#g&=C;WT&R z@kPo4WD_M}AIejfn^!p7jY6FscUPa-4)WoIq>*j9Whrxys~UnM<}f2T7b^MVt8lHsn#ujU}4ofMfLitrvW*V>T7&lPmXyB z4B>p;WglaU&KIM;ayOKf>Un=G&!oI}X{kDIop^o#m5KJ(SnH1kkH&TVk~dD!J|5TA zsP~RZr-h~F*?_F#7w^)L8@COH%yf z1@OoLG4>iklJMMF>z2s1gtYb^8@;q72Cjbi*G{)r-3Id;8=Ml1Of*&Zf?Z^)qA!YZ~RI zgtAT6)T2ILTeBgwYauqeE;-2dHLHR9Ry5xAqy(}O=BOY=0rVEwjJd7kMM!~|0ymk? z;8aOPD5y_RH!iYi#dHxEk~z-2&A%n|44I{^p!)6c+N~ygDFqmcnp`R=Q1*tIGIM!fN=_3vt@4Jk$ zvTcFep(Tu$SUrzZ79lP)3R;lPU>9141zHVTn9mXtQ8Jd|@zkQ5Z2DQ8oicgk1W&F0 zOR_L-OsyEoPg`Ml9-JWiS(KNNL8YkQ@uMddu>?j|b^e=LoG&^`5BRNpr;N9UUAok= zj6QEXolB?0sY9OT-&v`xQ_y;-Va&x=f+j}g+ z97+Y+Hdtre=bZp7(>hI&O&VI8b-^g|Ds5CrQ+0uip9?^yj193k`$Oc_?(Ej_iV>;~(!D3W?vF?jP~SJyz=eC9cl>cUK1o9OG{9&2cwg}v%lP6#9=k-G<7lF^(Q)-rI zytnhl+vHan@N1MEZ?aavCFMUWdH1?ZC>rWuzqCtu%(b=IKv0D?87QBj|8awcWg zzD<40-}Ymk|0%lquUY;sXLqppCWAY_b>ROG20spny}n1NSr~!@rI^9}7^Me+28heb z?VyM*U-DOw@olsAw$7T^j<^!<_-aSxr$*Mpd`@Mj$!~Yx>tqU{ur@P{F=T%v%5oa3 zvfpw&=>Z9$z18bMLBjL%T*BUz%oGpgbiX}j?n(WSF0r(4c48qVa3X0U`z*VDWnQOE z@KNCac^*01U0r6a+9c#8gCMSP6fggU%|*Fa#477W#iLcb^_L%kkI!6n8(v%rsT*!C5HRA{H~@1i zfG&(_WX^7UuWnrII$rEtxe*<&?-xvJ#pUk-3mca}%=HG)U~a-1Q=R2*+e+Pbo1PnH zbDOp+(4nnuuL`7%q_2~`sTdyDudKHWl(S$ZSbfQT$n;4NOduf%=gES1AbFLG^e^Y7 z3oDnXj<;h7JInb_0N2npuM(hlgj|=GUD(Jk-!v!R&AmNlH9nIKNh|Sj0M@&53R~oa zNb90F2Hv0EiXf?vc7G2bovz?Y-`+{|j(5P)z zU#mYRSuCvTu5gAnJ-B-P%w(p@A^ihfm`E*2_g7?M?V6*#DUppbp_sysHHS+#l5dKg ziO>z#SXd>eR+=xY^~uylF!V@XAb5!=GJ1!C=tX zIC-6j6$U(e@|ja!j`urgyDC(op=&|!8}u6TH05~>8y4p3(E_ouI-7xRU53t)^%uj@ zSu-J7P(FOV}_RJ{qFCHBtWxR|mySH$5Wcj~<9F&_NFiKe?qRx@&;%E&cCW1Y)SOvcjDA|ZZ znR%KfR7|XGE^i58JB#^vk^5tiC4*%&j)QOAayUd7sbd)tORfx*Iq1tR9SWBA0JMx#zq zH#chshzX|m+ilV$CqryAadr!)dX#aUw+cq3w9n0q8AQ3&W^1^O!&8(PUhE}?OQk6a zg;&0krXjBcRvk&scU#h&8HEnzTzzoH{JAPA&U<^Z`r@+1vZ9Jy&<=~b)q;~K$kW*& z+0g10LiX)3gHd?)G@e4ILSgH2?u^)zY<;zNALygy(<7`NBSeBoMKol6hw+?pvTOt9 zfg|-bj>{&9+-km(M_W$GN(qA2Pcn)% z@bb5+((NORorG@);PMRtl>h&&&Hs-KPNj*zjA31G6oIlVt=_(%DTR4KI)7zwjvI6& zXNJ3y7>0~MjTpVxUs;$lJ2i0k&giQq(aerjH^l)-<-b-i?@y)el@|0ZY~``t?H znJ_MppeXM~TxtLK^Cy=*K`Tmf5|&n_Q=T*3n8HttFw`(xZgVt~SPD~29DtklqI)j{ zQ=I$V_lxoAP|9K&D&pRsh{JGJF_p#?W_mfO)Qi-S3k%TVRCiodNy!1HOvMH%%&;cNWD$$9I%n`9beOak-C5xM(_vWYj2ZOz8%uL) zajut|e*)$&j8QY#hLsKywk+TTLby9fOSw=+bF31;l1($nBA|{Z>@Ny-A0sJsMbYfO zRrkeel`MVWIx3YiZ-0jB>5|^-#(I;Zk)6l5VH_z_6m15p_)x;gI|x3s!z*72TewFi zxH(z^XXbqs@Yc=^TF7VlBQ2;!=np}CF0d#hqH)3D__cjzfV7#hRi&j~pNn z&yaYCb$^$LoeGkf{;waC{{bHUPCF|8cShY}l?P1glC2sKC3^PoFG{`P;4efR|4&35 zO+zMA{UG_n&Ey*qD`R&8FEuG}`>!{xvZ;N&I*W%??WXm$o0Uw=?@+?6x zYbA3V>X3LPSQ7Qd5QpI2Z6w{A5amgDOh+AIKzfQyM)h^1BRP$^ZTd^XKzOmt&O`{& z;P0FQo}+2E?$6%e6c>CNWtDs7C`u$x68)BQ;y!;WeG!xJ+OV;T>pV;y+qOSni~&=w zG*Pg_X%AC%^tihV^9ao4H5f#!kKjl@Ngw6X^L^4_Fm@hAKu133P_5QvTDRJ;O7>hj zWOFTTS3jdI7uR4aDbR^>A;D-mokfSXy-ov6bWWQkN#`t6C6Zd&q}^53ueduKaT+i5 z9eZ(WRbBMD#FsnO0$&JU5|K{8#ua8aj5paB`!9@Lz2d_BNXf!MADD5!0%mUoURtBU zy=C+1pY^Bd-1tqP0cz*8K^cfNfmcbSf}+mDQojL-cUooa4g827yKXZ_J6o~zm>WF5zX_TB8mSyonHA(r}JZK za$pcZEF^2ve~&c-UD219>QXpOi_Gc^Ntoy5@258&u`brjozLKX4ZXNJqny5VvSCI!fCG>oi<9X-Gmv6)50Sa0yL z`T_L;h|b@iZcR7RRkq@U8Q*+5$Tg&shjzqb^5rIkPK?5_YCJKv8XmLJ2`SCC3Z7D@ z4DC%PGVpmwZPt*?_hd^tRKBpGD>SWZu*uU!#urm~>F8y3aI@)$IDE~o+l`EL(VS59 zIktOJ%0!Q#{)s&Skai&t;3B}Uu{c2()Lg{efZQW?4%ASww#dp`cnM!VlA=6W%yG34 z286B2WcgTC-Ou}N*7NI7mVs)OG~}C2r<-KvPILT=O~+f$n}sV(8sn&@q(%YontR?x8C9X4Bzgpj&UJ3DnKHjt#wwPj~2JKxaZ{uXzhLitt4= zue1pOMC-k!5bPbVVrgs8E;VO%oIFKPAexru@g}PKHs$j1WpZs3z%xr6X>Rp%@HDM^Q75-3;&Tfqih?sr1MR) zO~KSLsT8qjFs-ymx8m|fU9xZOu#!#jNhb;Y)%(1A-XYQT` z+$g$jMGpRG3}^oq^?t`AB<-bc8J}uat(n3R0PV9E#QXf~ZSP!`5=`z}CxQ7L8U8=e zN<sgeR$tf2-#HN}U3$`i~ZyK%U$Txzf2PNP)Pa6NFzPW<&n~C~fEU8;*0d5Jh=; z1f#SgKJ%Qaw`NA8&bvX>6PX^DXX|l?N#vm#$&opTDv9|D`?0jZ4BE-}UJ9W5sf@ii zrqy;~3Q1c13>>DJ@j~$!OM52zAnc}0Q`Go8Es6SSp^=9SQs@d{gg>d|XC>$<4U5eX zO~WJ%LSw2&b?`5%{5k>WB>_%+mlCmTI`Hs1J(w5V#L9n|O5{6PXLC9M+f$-(MXb|n zEV=wR%FWSECsT+9qql>2*IF9<5~MRIffhDysP>^I!cBGv?ga_7bJ~>^`zZKS)Ln9^ zn0lBvmGn~ls;Jri^nM7Nhkx+$YJW9h;~{Y$24Rr^*}qf_}}7!L#cpilE8&oX=K-PlsO&Lf7&DJBrEsB#o0*Y=+E0 zj>UwycA6S*>FcP$9V_F7H&oaPxSnPZLomuv+`}+RLm(?Qq`(a9;+IWhr4R2v%%(VV zMx4Tge@CpGuOYJ9X9ES$M=qB277NCY&Owwei2s(wyh;hX4&YY&kbT$#}y{p=` z*87X~+-fO<;8bVch)MUu`acVZ{0}r|#h)=meAM<#sI}0Qnh$Jfu);`|WrO-zB{75y zu11Wq+J={|!pS@Vtu2Yk#B8=>=^Mgu1dw8#r4q)%3mc34D;f~SY;~OfI z4H^MQ1p@IDJGb3^|62+)Fg&13&iDDV@ckG6_s^mK$B*@I^4_(-Om5IE`d36}3r)b4NC!dU~w=R2?18F(R%2l%B?aFd7xa@fcc`ggn|t$ZUBPaTd5m z(%zHD3qt>}>6>-a*mrF*K{#tYvsmV%hlmkQmYmB@ApgbF&=_;pb@?6rO*UKk)Mc@% zIP0pI?$XNu&jxf9$3}}&Ugv*+w#(KnDSQl^X2f3m3WZv0@VAvEwfK`P;@cV{`#*aA zGx}w3Z0Pu3$M82bb)hyPvoG@3WlE##Jd#POkbD$ybS9r5eR|x6vPd`dEv8#`Et6d)=q}LY-7Xs145%bIB-Cz%Q@0KsK6>O(91uzl z$$=-_*e_tOPs^hUZ6yu4OSblbc4nj9%Qi;)SX{EWBkP9D;CD?8BMN|xvOTsKC!#(! za;W@0791en>a*}KO#oBy;Y_p#j?chfeZTrXLj8n#*<58vcL5#)g&7sDJ$>55$GXes zZVg}ZJXN#4tq4=!-2`2)Ri1)l6}KJl@T}WUy3byc%_oFx(J!QKAZTDaGe}Ha>8u<9 zbj`=l?d~*UKgTmpBNM-R`cbJpsi*i~q+jwls=O&{P(P_nX@O)=Z>giyTkCItN1a~K zU_@xG13wgUJA9jX3t1N|Y_FkwmkM7&(KdY@j-tYmdDT9TL)fEwXwlR%*;fGOgZ;6p z2twiKGH(hFmP36#Fc8`PSg_SRjk#HQb>FQF&Dk_(Tb^@myx!l@CI(bEiP)wS!PPh` zKtws$=!J;)#N7G4;)DC*e02JDFU3Nc8ajUR4HJWUda8ctd~k^L`wz0Hep1uoW27vc z$nj9C4=dzk6qW#|2d^b-XkW+~qZLx8W2uyMV^U}&7)re8Ka={=1Uoj&INb~VC@vZ; zXy1+na^a^7cG34IN3w(XOV<^7n8`0nf(ZSB>uc(oksG-BN=B`}{>Bjs%|R4_zyGW2 zR?a{p1k;^ur!0ml!G9=%V&%EMzqQNM17z?pm`3!h9SJ-}rp0)y>NUae${A@%`%0p5 zLlW66x!rX}h>5(~QQm59I(MSJ0JY=0hNd8;Y`w?S37n9`Kri%gTor8nolTI4>>(}v z)}T$~^q|5yg(gzp7*t$=ov0Bqckbf1todlvh03gOhV)7<`G6-zF+i+8!kh>}Y#3u? z0T?t^ngNs|?P#!_^OaifrsSXOY!>F>(qDxrG*&E6iJ_jj{V_mLO(UPU78zfLrPvff z-87iOkZ2R%DSA*0l{7(oN=tNLflyGLP!3QcBv1-xv688VYH0gU)(OZHxE6Ct{M%?$ zY6{o*kj7QmLi-TB3qll3o(yiuq)J-EDmy2cr21GhqmCk4GT)*t^&hnZRx8ELJk|{G z$u<-8-v);Eu_p8YaqZ3q9m6Qh+(_+X9PS!3!V+*sQPssAHr7=cibW1tXdC264F zH>Q%%OgNFC2f`@MLa(x3>D$5WV=Oe~=yj%Su?TPRioVcB;olsDR(W`&&O z(n?BlyFi+|nUk)R5$-kfIuvg!Rm&r^$&5s#PzoPD@Mg)ILfcq}JQU;|ft`PrcIY4t zA#l8tSV^;pc(>11VdZ3a_y8sW+yNQ9l(hn*7wK05BMK(wu&v_)HPd6ejynmQWgk^W zR&71!JHu{r*A(7+y67w_ht`^?&b&}{?Po0fc0gkiL~efIkzq8H#Z0Sm=xZfmeR`NTIQzb3adEc)rN=7+ zliGrE1DI(nXRLjB@RG*msln^=c6(3k?L22(zNh&TZ->b)lw$~|)D($2xmO!>B_Rec z_iJ@v_(6?N)oXzUuwf&ccEkqF%b$bmQ_0#~c1Rj7#GGS=3dqw{Eg!kWaU_K?Yg=`q zpRc~R!|H=3JOdUkFNb8a3-c{VS4RY|g%5wQ3tw*konBw8(T{1HN)&DQm(mh?Ga*hf--;ee9a-3+Q&M01lW8P6<&;Qv!4c6Kcnf6` zU|!IC@K}7i$ZxW{aoLiec{!kg%buC@@K>|?%5DFl#dL0+zf+0x7`s7ygw24V{wIjQbb>swh^Iu0OqmCZ0^hej`OW$k0x zTwR995^nU*slLpWl+Sp_kKBPbz<*xt7LjiZddMXVYq0}+dMzDu>YylkD81@q!qV*Q zZVgqW{+&rhVQvjWz4s=+%T_!^MV;^@N+tE}u!z@$gIsAL;$ER!=gBHB0BrNeWO`h7 zjbRu;{YIH3{1`RrbEhJWDh9IT#`-Qp&5c~Dh#XmBBp0v2OCm;cH+`qgn(g89F6gLg z6YJszLfS>wm;H=GzspSvCiCvxHUc!2R{fb2Fvpb%N+mB--;3wMd>pM|i74@k?|>B{ zG8s6u<-VR9eaB;9<6jOVc#2KSadT$n5TeLoA&HtCKoviJI?Ju*zcE0X1#vf1@;&lu zD;&f1eJ&of;-oxp`sEKU{oVFM$`_a)}|kE6cDFLJI>{VwoCU8X?lxY%iNyarmcxFICw6bs#58V*FEt)RB&5{ob%Qg%*4t2 zD#)82vzNMJc<5YwfDSxK`J3ngC&0(<;hQ>W{2%31|MxZh4-wvX0_+^$UkR`< zzkdPK!^?%1p1lUNLa6XdKsJmT;Yg7YFrtRL=DFy+z;*ed`$N3Kd>5J=lAREzIW|x^ z>#vzizD%+nc{)ro)r`X;wTIVJ39%}xLpOTf?Q*eu*n2;opA7CHY?!tq(72$wMV%pZ z8Z;VZr%19=3r%3xMD8ad2C_@c-wE;BsvRbxq#2iXVULgl{VZhma=N+oqzJGl<%)CHnn{lFT)w zncq6vzpndA&_>-t9pUxsDbqH(2I2{ru48F}PeX4q&Z;Qvt*d79Du5nzbHd?8LXs2$ z*=$l6hkE*R?Q{5ZX=iSSk;8NK%dh(?g!cOQ>GNoZ%3aL9gJu9|LS}U$A5F(Jtl&50 zk;DP35a@wH(dUHYuF2U02V1;CnElJ2ACMVM)%H2rO=Y0|()>R^5-gppVP-(F2u>~X zc@RK_NYHDFPH%5W+?uxc<6AQ7+ z2&-QioFE=|2B5`~Bfl6;ipPN;Pj2Au*1pom7stJvK8&-bC;hbMWxWLz4NC%&m%&6& zEfR`jC<)0xHci?@la5q5n-tJl6T+-7aGZJQlJ$cD zmWA2Wr}I0GU4Gcd3RWx=io)>M1c|U!MogX{1A*=U?5axxGkA%~F6&w^E|&&uYbw^9 z5Gwke;il@4{thx2B?YExEIYvct=wSG_GC3Hftj{OX)Pe}dOog=XhyYV5O-l|*$z}S z1;ztgyODOeMVDTK;$#sO@T&?bPLr!H%)6gW;p;a#z_!q}p7Ct%ZPX~{r_cl~*tJS)%F@yyb@ZA8iVo~(s7yXXxZ!Y85pnW}m>=LApT0+XN(LiO z*c-SGh*P+rw!#IMK~pwnwu!)k36^=1BONXoYM@Xqh1RFAcuh2u?=^0^T)Zu2B>cUo z4^);B-F|5;gT3Vl!_wF!Lns-J%+4;-_l3p!#boX-VUdlQb>hG!Z@eT05x^~ORdCm9 z_guNV?tTmNurz+tJ&D{@Pv0%IZ%6*zkpjE`ZD8ub3L2S_u@|dRIo!bvww||^Ettyt+M>ge=IQz~<+aCmT;is1%2EfKEs!&ugPZ zeEc4Ov3E^%t-ZGF3BoCKWmiW69agie#Wxt^R~-fbseI{7j6t*4ew-h0BK?TZ9I&%^ z6x>BUZV*dQYi46LiNC4)uXt~*1N&Y0+oyF#`JFBB?;nv?ww5+-#(!nqPiW}ctPdgj zES0Ef;dzE+!^_~V?gF5R<1{gcxAIq^h=Ka$Mth)TaNbJX`j_$pjLT%8(c|YH3*tec zh(q6(`JSpZQEJ|*ZhI9>!aUKsxE1@;L9f zH0y6&lM3P06}s2nwmUbjFJ)b>KF>Elaw1pOPHs{!aB7}u3q1d9$|g|bG^i^jayHp2 zCA$$A8}i61Oy>IsG2t!(DN)=SPk;rJsuete}Q^fVlEqwJ;p4_`gAT1MVpxP!BIqUv2r+ zwug{XvSE;=ttDq((mk)R>{x0it}tjFtb`vK_eCI}Xum48N{&3CT;pzY-8Uf$C^2*p zxt%5z2wt6k|LXWST-cVeBUkjBW%l&&O|c>Y?vpS6tPoN{ks>~{fdv45e6au|^gE44 zxc~5pPlcthejH^oOfEd=H5)7MR+_4~J2k&+ZCmzK(N;=Xz~s`k!L2)Wa?}_ z`I<6&{=t(|zY#-}nj*V`jXcOJdz%k4XEus`hhqHm(5;DG*>>8S>J@K6{Q;`c4N~J* z8B?0qGP7{SYIqQBfzgb>4Q=X8N838rCKu2N)w2UBIcpB^Od6p&jxh!N+`}ybOGwTc zRb~qZcm+@bQY5=&uKnm-z3}-I{v%egSKyr=;t0D$CQBgA@;ds!t&2tvW4!lR&+t+P zvf2W2VRk*a4k-mT(3buXDUuG&QUn7eUNt*0 zzR5dGFQDx7BZhQKMa^KLtSFRnWdy3M;b!DeKecA*LQWpA9;M^v6+M847l;1B7T*ap z811xj&YnB}t$)%>dP^9$afaeE#O-$0aPDqd6Vxh#MhLY2C?ibB1o{FM&b@QC#Z!3N zrCE}0zRe6y2C^KID!`CCq@YhJdM$fay?SzAu||Fw$iBHl_$DAY3IY%8ct8q-b1)TA zvW3;7Fwk06BrZ$Rz>OCS*X(IcZVx2e50!}#CEdNgVTFEEy&Cjcn2fEu)A-*rb#D2j zP6}l1%4~u@G5ofCzMz}kox5K|3@5)4R42N+|CU8ppFR6UHvYSK3ZELcWuvi8#=2(V4W+8$!MY6k@O`ZshLucnBfgtvIdkblMMq0tYAWYEmMr{%GP8~bd ze5oe&qe_9Tsc{5U^*}xI6YYdo6=9C$XcA_{e{k&OYJUazKX@bX2y?l$(+SSo{Sk1r;Rc-C?ef&_(vyf_kfUGh_bwQ0g4Z*3;j-2F zG0Ev6Dmr&yufcai9j=QhsdjtaqSv2n{Epn8vgob-(K5MG(%8*$%3mLeduy9jk*@bF z-rxgS`~vg`WRuThj*yn(Kr3|L)-TVMwAl9@wuV+oyEue6o1p|k@TR1==n_W>(+Xc6 z7P^em3|$Uw;^&W~!Jo0}k8QPWvrYtcrOb3P@(mzLn7_nkqMKt?!Z#U0lJczt$JbY4 z7k|(BbE;2~u^f-N2Y^u#*Gv{+L5dlGivVFQLyjO7olhT-WWivGv0^ff40c_l^H~W& zI$YLR^iT&Z?HkfVohT#kV1#PS0Xw=Q|ruu ze@vcQf)4zc6DvqUW#i75&z`twjjv=d{S{31hZt0`m{A5UHMcd?FOH>?I2n2GZoj~+ zjs>mELmE&4IGC!rFeJn5*Uj@nQ-&}mz@eT4AnPA4&3Q#B?*&H>@&E}qGh_DyW{;Bl zr741^vlHh;z%|}l{5xtFeaB#U0#4y=(8HXW>`_ilFH{7}y_}JK`qSbJAu5>Ryd3L7 z>6okvTNtiWJK4S#29tj5V&rrzjpaRnoU_Hl@%(_d~$s|Gz{`dP{j8GA{NlCuh(b!Yd* zcv6)UR%qIfB@fVqhjcF#hUIs^DmR4%>eqkl;6M5Zg^n0N^S#0rH7FW}RiiSrT)`a?|I z8X_!#mg14kqHjBAdYwmUd0Hx1yJA==S3zl5*icGv%a zT?zkeb*B$YRKc&=Jb=n5OC~5Z?q1tZ?gu$&GE$pB8N#`p^1`f5P?qRQHJoHmI`ZNl zqOVcaN)c7mslE(RMND3mQCq2-sOrU4%R5-O>8uYk;H_ds!`rwcfM|7O1MgCqO~WQs zrHh0|Oe=QAwIgNL7_+tZps6~an1X6kFoad!V>XrX0Bcp!3=HvRZNz^3%@u1`I5e=n z-HWw*2eerm@<0(p+WSr0RDG7=Dtfhh|x%7tBLQuc;b|CpQgn1OE{2#h+h920W zX?X2=PY@ajbK1qwWS`^|Y#;f(*4d`Nufhof$`b^fsl!(giT4N_BNX%&iTYn~X|bVC z^_m8rhZ(#4SO0VYkH5h_TRy$nbe$m7dZC+&dUB7G-c6fY&z1&!KQ zZRu-y0raBRUF`ic*XIJ=vy*_TSvxly3oWh=^_Y_% z^g1x@ivjM*?XH8AWZ;*yZ_I-H1paF*9{Otp>w>j(M&h%{c+z&DtH@A_yZ$qR0&z1j z!DtjFUvVq)FH$x@4u{6MtAKOAQSC>R9aYiDW@h=-tXm-wtNz<s{&(6fl?V@J*efvM?=jrw;ZCM@bgKH$UQHz+G%1yOmA5O<^JQYY*~Jv{>%&er zo8ZZGqU~wP54hW9?1<|^aH#e?belg4t_!nfP&5vy#@c+0LT8hDKRL=k>An%MfHYpE( zL_TG}yr&$wy?fo#xv}M?PWF=#!i66I;y=9KYG;D89{pjyKHx@EPD?yOp>@` zC`#K%(^5;+z-TqAao(Q_ebd&UfMi9vOoOY3IROwUjftVk5u4~_v;{2IDj zkiK}O<09&grjWMbr)F^zpYjyE|_&iT`JX&cC1a_m7Uu|D*-~q6Af?ZPr*Yy3SM) z+UCKG@Pe&E0I z+bIZdhh(kb?t9t$-goQ>i+eetnWLWw_x#-MO(ImiEbSG&%xmia8!UScl(|(K^Pv6# zz4q%>SUfuj#bQ@DJKl`55T20p5svhasvXfGE#x_prO)WXe2t#p62N-iD=S?`(4cnX z&us9W*CTvNJD4-VogRbiDFEgl;1iXV;rSRb310rRPX}R#8ix1~GoD&W`X*BZ7@YkJo@708U+-lFys`l$kL%FUYtF z-+f12P5u@l}!x?C8#UUM4 z5killdT@OzY=b|cQez|KzT{I?mIcKzW;)hiGwH4TVK;uvaBU}x2hACUn`}9v*j#P# z>^A;39-()y9q6r^v&ykAb+ZrV%o%XH&<;K|0?T7|xyjGNkh4C?R|2Nbty-ZE*EQH) ztV^o=p@J5KB#(SkEA%)h32og)@f=7t@wsYm8TkQ3yFgyeeA&2#uL$ovuK;^Eh|jdg_3zi;WJ zZjfqHT$i5rw)>-F=$fx|rY^YpYo2vyaIJ$l$1_9fm0L7%!&^d_in$AL-la zhcoSh(fE`|E6uBPtUt91;AM$Q`G1-i6Xy?zS~}{E1We0uX8pH86a{WLAV8)pCX?}h za`9uIykI2j0zQc?Rf9Eh-&0Gm+WrCc+Bp)>);~CggRjl=ul5MHW?5Q9k zRyR)JnY?Rk5!{t_SQBCY`dh_~6(0Bw)AyE({8pL$`-R^B=<@zQ2|WL&IX9kf0T@Hc z8Cv^zVsm~C8#&S-szuOvRBX>*9m=^rj|Mw^Z8NdU|8#?Ch1gj~|1ipZa^`qSVRlhZ zGW{-#@#yU^BkoAOP0zj)WmJ2bq zuz}805i2Jd7n)gLG|*%i(72j zOS|uDn6_w8@Jw_LJ7qIaNu zz)M(=THN2tB?HTVHNh_r%lPQM`VU!4Hc`ObS&DV%YjqK!g$5pNr3z9xhY%`i=J1uJ ze-c6JQJ#zK&`jjDXs78@hQ0$`N2%vnJWR)0bX?tQU9of_BRZIw%8Xp%B8PGDb9;kV zi#sO;2%6IudW;0Eg;N25kJ|F>H>lTWmuChAUWWM<^R&O9ppw6RYa*|0%m)6 zwxu|=GD_oS>?^A@r_U%!|1i^=O6d@-9L9F$xbPaUCRS|_3TKt@{C^@TxHg0#odjoY_xOywUzw4Jm14H)m?AY^;U zbgnGeS^~Fv6$JLdy{`?9zn#~KBtp2`F0uJNKw7Lgc6Z8{ zVFG0HaOnDfk@k+=nQrMCXzWz1N>Z^Zw(V4G+qP}nwr#s&+pJg>Rh&9+*6QxvYwdl; z=sxGe^8=nS<~8Sy3+=C9_A+Ztw`ArXkAmju8X!xWn@$bcXzw z#~qVp0E*$tEDLVgEK&S|QH#Oe_3vy=TOCwzDTZxBe z6L(8Z`R6&i^-WG$me}SF+>Cn`B9W8^bX|bQU5oXwZl}Yh#bJ?ohapb-vtoItlGU6{ z(tSh8ax-WPcO%UTsJp|zdEC)_c-+x$$g?spzMsmscJP6+CNQ>vWPFac8J(z!XFO#( zRcn{oWb7cg;k!q;nsBAZ)}uSwk#+}!<&8NXl_o%>WXqe1t9F;5x?us2`1`Uc`%7_D z*r|DgZdjFC(U_Y2ptbnqxqDYPl@QNg&id82P7HyvPgy5hzZ`I&)AAJO7*voyrajp?nz>GFXKT_6`9qC?NWDZSo1c2N(l5Gm{ij-S%#)ggtN@n$ounSHC zys#A)361)f`-@<0pYFEz=YvZYB9;2-k?N~QnPNtJS^#tx*gl{ergSSJCY?%v`fyT< z#K+>_(gZp9yTCA8kj683Yx}KrwJrCX|WB!fKBB}A$k&Z z_rCyR!`!43sa zC)^Y#h6IrgI@lx1c+f509x&UdJkY$lV_l5-4Q`WS8l7CkJjveHKl_F|gRwQ=gIE5g?JE1+W-H^ssuvdF;@1W?Xlnwi2$yKq zf`m^&E=TZAJo za^$ZwrOHL%XI^GS33Uh?W7TK=vR{J)d=oMHbYg$k9+?!F&$$2~{t<=#pBozg56m5G z>>bTMLIp`8XQ2n^;Dmm22aTw}SwTWI%Fe|CGx*ZiNrF1d6Sv)pI$xe$o=C?h;xh68f)WHS>4cxiSEhtpHFK1N_l{mX7$x-~82_`fr#9 z81MZXrmO#n>BKKZU8w%_0(A$93(1j%l&P`5w-%oj*pK3uXh*A@ja@_=${Wo?FVqR} zLQU0+s8_eWI*L_ts%yGEw*V6xd1vTV7wX@mjsn(2vJ6mPAq|$y8S^Eyp+}(^1NAe1 z`6W$A{A|}G-n;T+kjlg0DcZX9*1Xb^8?ZtQ9lNqZL41VJERfL7Xq1&IAhv3KD;f(s zf+^5>(M1IFsK*rz@ApcL^>B(kVCmdl`t~*@RgwGna(hb$u@S_pA;)Mi0xi3(hZ+3% zfLy!xuG@C9e@U5UL@c1hh{H(GM90E;OFn(WmEGo#)JibiI|CZ*_NgF0GF0D)f{IU7 z>Q4_^YcUF#46KUlW?X$Y=D65?Yu@^`pMi>%wGu8GA)z7CuELf1G{{)mD)ep-yI2Lh zSL*BD?+w+PkSVlDB>hlkR0-h2>Sg=baLCh2q(&{o<6WjjOxdz}Zi4ipVhnOms6_Cj zpeYEF!+HBkvSVw>;|%G10h%j8^JsmPYrH&FKZ-)oLxb~FZ0LFX+&#ln1b!J{qoOMP z8qU5}JC+~tO!fN0=io78AGeC9wIgyj&gwQmZAz;s7qGnHZ}P%LAc9eWoa=*5{Wk0` z^8geTV+6G79MQq?3ldkrXsw*(R8+>@4}GutbLnr$==#@{paQQ>(s_V4wzXbDi|UD= z#;JwC{ZAk{SHE1U(l5Aj)^>KqKi8p`Cyx|8tfN&zA%@{_HVsq2f7@)OJ&E_ZfN0js zx|aTsmbMfL=epi&%STNY{7$il3@^<;l)5xSB7Q0l0xNsQ!^B)LPWYui$@$1AAzA@CP|C z|Gy#!e!#)#AMA&J2^#)cmi}MlKs8nfBg+%rKzv1w%R!t`)v?~h_lK;h`VU><^Eds2 z%?^*NZ26{Vpk|9gcOW-YM+?1|mzQ8IpH)qt7k7_@zNAxz73ZkO@9S`vi2%LqSCyeE zt4Ud>E?Vc`Uy` ziV;%0l!XX7Fw`UZ2RV=^?4RU7Poi_*X9CHBy4B%`2)6I><88_LheN##-FT$Y2G5=S z3~oM+{dY%~6m18wv3{KLiBauWg;G}Ln|pf;roZ0CM2nzsP}z|DVW# z=Kylx><2mU`A>47#$U*RRV~Jvz7E?CM?u!@hRD;e&SRakQgapK?g(=Z6j<|kYnX=q zUFjii<+5R_f$&i`qs)7s`fu^6ur+n7dY0g>n3D?zMq$^O;aR`*1evqzPqiK)v5D`Z z>{fKpe*(VMnN2&HTbh%F@qan>Xw{h_<|WH!dKA=!8;)1T!7ONpL#ziOE|E^H$KaNp zzp8b{v(G@;zDCmx^hE_JEQp(fm3f!<`3E{_h*4J19$P3R z{Aqwk-`}K4Lgt%5MSzn{54h<6bII(#pKOQ!eYF2f#eJa+q^;{?&KnM*hStkS79hVU zmW@OTr!L9Y78hIdhkkm9HXKcE*kW2VTAu4ntVAA!W~Lv z({e)1Od#P?pbj(g>-~md64;^1viKxy=@?FzicCu3!2_P{mo1ZG%!_l=AYvjrH082_ zpL?;C6VfrwDMyZ3yzgqRg5+m9Gc7>_X$nYut8qA?gfHJnh?Ro*;Y*F8${OV^1*i#? zc?~ktE=1=n)N`YmL`wB6klJYdokyT7T^OWZXhg4gI(0Rj+mx>v-h~&P``+yJ5a%N; z1YHHSs^@Op5Pmo$i%(ORpMJL{OXTdEm;rUBk1Pl?7e_MHq_d^=Gcx7S0Z$T=7+bdl zack2=Q&xf0o_#-YBdO++z`v2I+0uW9IXz*I3Bp-ll9nyGslUL|DPm!&^15;W4NouF zll$T7c(B#$m#&ka)v33=L#{X6dupb_v$d4(2wPI8aZb|HXQ@a5;p>d0zTdmOpkm}2OH z+cO7Oc45E>u)%)Npsbt|54%0X)H+R6P1|A|Bb>xI8a!!bbM~EN9^+y0X+g#?`W;NW z)ES1%{65J;+CWS#I$J;xxFdt%A7r9ZNg($5+jht21Ze7`++hWvK;*wFcPz~u908d* z4i0)IAE{3N(vJU00H6JE0RfC2sJz4A|5fZX!UKw(@IQ+kGAwZwI)V?I;dT3|lw$9; z1}4T1&M#$h_6WsSt*$`bSA`6q5RUM;Atu z>RDH5OLu-zAUeUzxFuqHTA6)aT%qpR+jO^S7W;nNsh7mc9v6@-nJR{PEV2+jd0*$d@xjnDk0QXrPtL(YTsIVJy$v1AW znmD~l3dUxOTS0TGb?GPa?@Ei8od>izpk+-{LE-P3RU4;IaD@&@qm$IA2l`EMV;6|l zE7@#t7B`ONEq=ja zbTEKcl`Fw&diy79y9AS+)h)}h*BCBC<{Ysh57I8Wk#!iRvS4#TziLiS{Df=?zhQGV z(D(FsI`5Mw9~rc;zwL#q8xC^C2)%iL?Sq9F&+8kF+gZwrGka>XKci^S=9cM;VBo>j z&dZTUD*bKTm2LCM1y>gnM8ylY8Ai|Kn-+zsvvNcx{;Pn0YH_iVOch zL>J|1{XypK0mk~=)cK`pV^q9{{&RGMNB={XV(_{5@76*L9U9thudeQ~k+x&T`ZLbQ z?}{SU;2(&9H5eklkYi@j1ky{FZIKQMN*W0k)PVH6^eLQhs01&bSwG83;mlAB_&|ik zx)4|nQcDVRBZo@w*8mdt;EZeD@O<3WXP$Uh43i(yUxd1%YI;2(t5&%mb-h5_2QWOj zxT6#Tv#CAG)r*nX4ef0~&jToNPLp4$TTztlx#^FFR(iW>5f33O6)lLW~*tkC|p?e~zRStLaC=<~%$0Up%b2y*PG%S4jkWR&ynCkIOBB z5jMV#8JxLIKR(~61(PV~Mzp9NeSzCVa0qs%X7Ywl2;M90DXn8 zB=CZJ;F{gdXNhHhX41-d6Vn8_qUxP;qz;pc(iIP^mD^+`pWO`G;I#FT>Vz(YX=yJ&|wOhaJwq)&qlhmM6=fj2*abNesx^UU@IP9E}N|BsP+m=dW zZ5Ma9Qo91=J`oAt2qFaV)v658#h{KMM$m1O<=_yV;Sd zn>AiP!b^_t+85)}{zeUm@u$5U!T}rf5i%)WSN|q>hCowpv+K={@|5X1x0B;bpDCeU zXA=3R@GX-=uT%SuP3jNfo0as3@NF5g&i-}bNV-CIpvIBU2H@2eD92l+KLv;tnw2#* zVi$2q19;{<2MLA(xlNTG|4qaR{8iE16rc{W01*56{;S*G!BNlA>3?1ERZ8pS0G*K6 zm5SwF0Q8{jRD^6PxjZcteW!N)-r?jd+1dXS{a zYBY<`)m}SawYX@qNf7!;Qc7sD>YzKG2@5`Nf?>$lsQRdEL*PL0VIBRcWN<*AF3dhD<#HMa57pz>h~X)%@~^|9 ziibFY*>EAzA-)-#k@<;Y&|X_f_``M+SJYs2-zDVKR_{?zgnOBbGPRlvweEKlO&X=0 zE~9c^+j(edmyXV2&KiKmXb*C3Jf5uHfUR=IB5sgnrj~N@Uc+d42{ekz5KOr#eUf;A zV$|spd&a-b{BDHTc~9J)IjMieZM27sYL;6(OfxWZXkV*!FQ$eN+)JeZi)ESspDvSy zn-5AAHYZJ@V=P2+uFy)RXYLl156grOL&f;6O4O+iDaCg!tDz}AKNw)a+KkBx{}|%8HiV=ur|cd+eascTrZ9v* zqfrVJj$bBWtLy3-R+(LX!Q5m00++AL<7yR+sXsL^a=Bx3v8!(y=i<~`|m3SQPB^D z#6F)+Y?vcH?U8&3p8<)c(QPqSR%%jsm?=-C*hioFJoMJ!87dg2zl;^;$Cyq*QGnqnZn$zWykad}d(!#IO38;ZkEjwC(+hhR#{{BU z*S)6BB;kyVjB}7ZT5otosDHZHqp^v{67Y((G1Bo*Ikc=H^sEt13viW`iwi916eIFV ziTQuqxzt24n9o@9%q;!=X~v_ytH1;5G^nahxT6aFic)=KaxsU&EP3JcD~CT1yDdF< z@NfeUrCw-$YW_GK6C2))5tx`Y;VwxniUIE%T%ALP#^vs>U3hU7$HFJ6%**^QVZKGo zww%b?VlNHH^#x}=KM=1aku*2FPr;8)q=RNaSMmhl|L*6u^G0-i0(hMc0Iw7Ge}!U4 zJ(K_4w@6t4BK5k?RNy$&a>Hi|`bY>`&CH-loB%~yU7YfXyc%WWnLm^tOWvLQaS`vJ z6gKkO!V_$T&%$a`WsIs_>8EBU_uIqC3^ie_9RCT0WE{|pVy*-__ZRcyD<162ZrARf zqkif54!SXg=U_t`9MVX#WV90|LL*XTHG(Kr0Y9jpQX4uD9I;3Rb}K;XNAYvFvanUT zAulx{L|TfnW@=RC7Jr879S}qXk%@0YvNuy%fCVHyXLHwUvF$YwwaeG4v2Lb?IXn8;uld~? zQ^Y5I=k#)9G0e*3m<)~-B9#PW8#zM)!u6J98HK$RSYzeb$KxUFpUl_KpA*MixGIYa zrkCdY@Q2LK8rZ)`X(Fo4nE9pY3eFuisI69W(_(e`mbleeuhNk7iGLmWi@B$)VLD+*2(Q$)JN?d>MDysS!xW$Z_i=}E zC4{avXT3){x=shYgw3PmXMcMMqu5N0>Hrur2J}5*|1E|b{x#|SUoT>k;`+xJzze`Y z=oy4q4&tKcrQJogX;YCf=? z?E;iCjX9+F26^*i<-hDmg(&#tygS2YTo+ucJ4 zx4Hdo@aApS_j3PNMXDaLefpvGNFbAD#_Pn@V{x$IX`8wGVku*1TP>1wQvPW3181`Bx;VclY63YZ}cteY?>|sw%Q4OT=cAO&I`B zD@{fviuxu}O+tqo60O2dVWEMj#N-FjritnX+G-P-MqaII# zlRs;0yw1e)%i2OMrg09WtZuY~YuejvkOu-JosS{2+W^m$c4<9-&FXNLiLgN9R~5iq z>{{LZVL#g%c>PO6VUZ>0Rk8FYe~4^SbA8lvUxM}*nKh-CyWcx<+L`XQOflOA92WJ4 zw_G>qc$)!v5UkV0p~dDa+^8uC%EF@sC}UL~%nFYefoD?<`P@!JltKYo5Yg5*;lsZ% zIJmD+T8L)|vwH?6>1fp}5U2_45v;9X))3#(k z@GPQh>t3s;qEP8D+>1aY&Ud^?JU>m#)EN#hJWR++=wV*2I-PbUPKF7j(o@eZ688PA z@formwaf&-;{Ly;;{cwP{{syFoB*i4B4cZ!JiFSG5EOoZ;m-+x{nyik$fAEN0KY|N z72bcduK>_-R+Gw=@%o&j6cO-aqO7TLyuG`O|6BlecZu)FJ3-^Li@fewfw+7a=O-1| zS!giUOUQ|n_+sm#nt17gel$H_V!aXK&BB{Pq1|0x-kx{jKkEhXDUYu?1Mjf@jBZD5 z5~t32*+Jk(#L?wd#tRCe^YieMKj7&^LI*y~po z359p^s_8wqzDQWJ3mK}2+>^BeSikX5GZVw`&$lSR;^Q}0}1YRNfh$}lE~N8!erzEI6pZH zamnH0eJS~|43ScXbg=*}#h}}y5$r8q9;=->g#ZD;`3!|f9X)QI@7-};>%nj&DS)p3 zmCA934$nOY8(^EzG$!~<6r=G@RL|$cehuDb+`S+<7dS?wbBQ$QoV^;F3Nu zWM5+YS{!7}VMBGMq$^k|iM=W0l_Gu>bhLk1{c-k_YcQ-gP^qZ1UbMqqJ$}-5+~89U z6vJDDumywC-0$FFV?AC2FN+suXJAxv1Ox0XC>I2wDS9hdLtavwo> zx!jD|mlUFS(0(#dMRpqtO#u>c_T5W_#xP6TH+q6=Ypb!+o{`=`sFBe>x}yM?Cg@Aw zi9j$VAA6H(o~CrDmVdkkI^$L+9#v;af}yF|1CzvkI)B~yb(k#G=mO5Y0YF*8 z@Si^i_BKwo08@RF54OKT-v{*!ATEK((YJ-~N+j8-_b~N18@)sJm!o1wbD}b!C^DvS zoEJcN3-TVEW2sHF?&g0li2gBHhr(IJu@Vm`q0(3j8c``_mHKW;eku`2fU~+C2r8nT z!&7*Pg(^lTe8!Y3PlQA@qL{`)gs$s~$%p_p98(kFg}(f5gE)d=@!inDW@!%JKscGc1ep{o#eB$t`Jp(s z=j`RVx_chs8FJ?+W$Sd*i^W@fm2kb5z-Taf>f1wpUDc z&Kdm9QH9aw@o=!v?^%SOd!TA)SQ-82r)dZ>HHZ8etq#ctsB2VJak67*80@2a`KaKO zXu~jmH$szz{SbN`hvY^o8_?5jFgo#)40!VKsYn zJ_qaK_-_@>>svXFbH?so3 zpD0;1-igvmueHvuNq?_Aqb$q#7*!}94ByZC-FS8bQjIhqTy?gfU~0j%V;CZgygZC` z4fK{gX8s%$9!5@5dhDJfs1bcXbF|x*yTw+hfS`UiSP#m*T=%RV!#1W`{hmYeN|hwW zz^p=OmII~jh$$J?0Y&vo4dabnr(rl{bGX6T5vV}1?++GamIJCGwl_GhBQ0z8{)+*R z_^RuBqMoQ*^&jV$$9PDxl4n~{LTW79!Z`q&4+TL&dtq0akTMJbLz9nuV3NGdp1+>g zge;LIU_c}P3b?14|Ksy&Wn`sqWbg0?b@JoLD$bh!ksha_`HC7~ay+gKheciBp`nv} zNdmUNW>0yzG9*7FfK|Dw8+nhik8(!+3Jb&i+pq7PycW1cXc z+B4^1$BiT3KE14N1kHBh*YwW?6+|AU!OD%a8j&F5+H2Qy+Dam)BSB$-nRCs6a*qVY zGqC_NDU0v88u>mS&+d)~#3dSo35(KoHZazTHp31-QALFOf@R<)CGl|nY`whRVh`_jy5ger(U%^(_sS1G!$ zPfp^Pz=pZ}wMOO6jujiV{N8}8$wM71XNL@__I}E2q9G2%*Md6plym9quk$GqAX=IQ zyObA2?Lc>>iRkX`MZ_uO&Ji>1`qbS@IR}KZqsW7wV}XZJ$ECQtPwO@uS5BMfLyEJM zEjB`4hUhJly8VOfB-si3naIaF@kvTBF$S6T42J9+_LP&*4x>NMMBeP)(isf~5l6ae zPleR?&lcOd08N9kGw2da;ke#82GqF-!tv*KIS;Ny=7}8FI4ifwyK_%XZ{6>7sv(7B zl6z>|AY?+8r&By-I&~{@T)1xn8G?0<( zHZU;GxSPvlty1ikxNQWI&_dy=BpELLgnnV8k0|J+8?S0zbwAqT8R3$t;Xkck5Zj#B&iy)-^p>( ztS>goi_i<;x5aM|s}>9<7in@?{ngmRMa4;s2$tG1*K9*>aQ-O$6lC-GvQ9MkgOJ23 z5~-)$Q5Saxm0779mar|bHvNvlDwH>rSp!@|RWrP(wK?S*is9nzUT9j*f$!6w^SSm3 zCRKTxI@zzBppf|R%oFebW+*K>z$$DF&_h%p0|C+f7nu5E9SDF^k&0EsIve8qr4GSs z5q;}BFmOuprd3DcI;G{W9jHE212@W3)gk#$0w+E_vl-N*5}6wZ-}KMYL<`c~j8WZ> zSMg<|z>)6w;*E77iKV$Owh$LBGJ1M=6mU|%`6~GvzevaolqO8-MMTTRAI-`-1UA@hl5s#k4J#+ z;`GFYJNkz!fDhv@{Xpot%T+FXSW@&CQPIxM#$&mW%?u^Zi}Ly9kHv#tD>C-T4$>ZnQa+rEi0h&I(?2(wM34j66;ARsTfyx*BI%I`PQBXX+oo z;d}CTT0H8ImN$jEHK#0g0(iZK$J{GuLL9H(=n{N|o9V%U?Xy9qrAY|rF`9`s>%WxXWTTcu2dIlqogw;m9S!f(N{WJ;LDomBdh#_1+` zHtZEzG2Fci_F^XO$+IYmd|semT{9g9zx*Y1A8nQ&PP4Qpy@;3zy6q%CsE87>MT|@}R$!*~jKMEG<`yeP zCtx8*gwjL{@6KGnRB${fth^pe$s1smd%R7o`MUb1lsuJY2H4cotxi=7=R}X#1>o-8 zP^hc4W)Hn(kG*OBSeM&>SaWaIc8mT6EgF;ibE7MUZLlD9Vnd&<&ia8Z=#@~ai7|z4L3RG8oL2nPLtiCXY z?6O!9{hkjIvcKTdqo5A4s5)sqQ~#1cbTyWP;EZfJvbnJQ~Zr7w&In|-`8`jZh(fk93v2?+b6VqH}RtM7qc=~a! zQT^m`>`UzGZ^CpLyG}~UhwC~_PO9lwuaczS zN(2tC$?uCyG*d;1ycuJ~KfTn^(@n1E${3J2yL!i?cEQ8lRlDJrdhISdQ1ZxE1w|FZrL# zDkE!00N-54(arY5xQ8UF4<>*PQRwO^{Ck35GoGwz-U1(YBY43PqN5e)XOaxm*B4Sd zX-=Eq)mduBTzJM*H?2%aB%2{sUNb^h!npU`+O5Z`O=YUl4#CTxi~*(P$q&+F&u{*) zr~!FAh-u%^*{$%RT9qiSbwb=%%*ccjRPi0b$4z^Y62tc;k^<*Pc3p!^AIQW%dD*hm zX|lcDp~g1w{Due@IXME|LtA_C=fB{sOHdFF8)~_|GmMceE_PO{OZcLz>H1W%Al`jpBwU9TNmnG8Q4>cj0ZUKOJHarwpx7&5KMc&{ zXqdXBW!4&>SL?uQ3{8%yQ1Fh-;DFg)1JPB&r~v*9`yGzx+x)ay;;``i{nuW-pIC4Z zcQ43rgR=rR`I^Hqp{ub!uoV!$ppQf~U{k|MTrOZ0{2b_-LXCh# z$apWPk|2RI67k}SAd8uQ#e`Cn1&;Kb~EN;koWW*R+U!D+B}P^R$O{U zeQH%EBJ_h#9l_!i1W5@#Z-8|Y<^yqvUMqgovgvARptizN?JZ=lO0jy%X|r_Gmtx~? zFGeHQQ$iVc#pe{o{#<2eA3Y+kLC(`5#u_51A!TQq81hA1_5)(v+9~2bq4`Ko<79P2 zxH{lIecs?QMRQ;eC3DpP=@|CVJykIvA#t|p2KMP9U!s8T`h>$kzkc2c!@iW_ge#8h zC?%q97|fdzHh5y?25FRo4x=Whg;EaqlPRQl-C9M|*^z_8$#sWj4apfM@6MTh3SI5B zC|Q?@F_M%np_(K{2@-?FDngOAdqxXkFRn_qXs!&)RsZP|6(58K$5PtYTZBtIBHDi* z_ju94&E`WNLu9tMu0izxT+wo+$!Rj9j+)3mIy+@;!u=)G)fb6hn98DZbbbO@{Ff?+ zhCS8RJSL(9s-j`UfI9?lSZP0shLeeceqFW*gjl}W0@IOwTnT#hhC9E^304ZPi5)ZA zqqgkScVa(^0kNS1LDMb)jk^rE7x$e28b99c?mwU1nRn`u9d=dEX3CNTdJRLQx_ zAX4S)3W-7#!UWY!S!*ug&4uq;wH^p^sjk=mSG z=%?q9K>PQ|jAFOGu(Rx5T+Wbr+#B;RaG0kmX^#eMs`(O|HT7fc&{~+dty8ETG>*d+#fkLn) ze_D36<(yLv%NHCc9tI0Po(sbI z9Qxvf5K>J_mlYvc%uyDxQPh-=i{!m3wtl<#K?b*nt*9JoQYq%J_#VU5jGVJS`n8t{ z!~~@H3mf>4N&EP60`&rL%VT_iSFi`HsrNa6P1ok-Nfvf%bp3m;(0#D zdU>Nu=2${W!_`x{b5mV3_=v9jCRtOPtutp^N$T z_lx#sD{6M?6U9j*r3W|!UO5DdUd>E5m!VjN`65)ybZ!-^c3zx_)q1y(_Gq(=G1<>X zn)H@>sUf+BzW6(L&wg0sbnGACzg3iz%K}bTz;$Kmb1v?L{T-XKu0tN7@PKsv4@Sd{ zcV9BJwb0e3Gn+2C;7x?^pr=ntxWL?dRBMhnH*7ET5dp^FmfM!n0tUIZ5E1@6Thvh`#?<1!rcC_XVg4IWv`T5yd;wssx?RFH z7(t3CcoJ1xJ4bkiAVA@aW(eR+Of(m)N@k{oenYC%b|ZO&==MVmm#>?S^&*;<^meY# z*eueuc6K=Q+eSVH0ipimM}= zW(U{S(sAYrwPIs}N+Kk2d_x1y9&O-_fH)}aAZ%o|EF*~uyqsv?X)wBWy&GH7C~-e{ zCU|Y|-uB4;o9j124_xk}_6B-Sc*PT0qZhR|`m(D%`)`Qv@ZB4H>11IDrd?F;s6D_j zpXpG2A}s!3O;|@zI=0iiLqu(8S5@gWyPd19Wj3=^W}8Ly#j+X0024zq_A!1%9dINt zj{E$LWCG4CaML`cND}@_f)L?Rpip?kDj!j&1Z0-)US4x+JShsoC9kHwChA@FW(&3) znT632EjWi65SyoDJt|Ql5_3Dqq}*<2P=4{GbJm?;LK9B%pmp&OYboWvT4%g91oa#X zJRKOWRQuz~F2)Zmc|~*1^$ROLEzi4in9q8W0%H}M)@Rx~!_m%8jpfcD{^gp5$tG@% zHp%u9i|jEO1al2?=#&z+6bgM`8I!9cf#P}Na8q`AB&aRz+}J<>bWG?)?efv(GCrC~Rqs|#%p zZn)N{l4#dtesfJ7FZoV6W8-rw{(hRqWr&V-oC!g_=AwA$={V|M3ADH^^hT0}zOMUx zY72_fHn6))ii;yWe^V`*^O9x7_m||UAA6@VsZ8I@;l0uLb1Yj^K?e5Ka+2t{3c@Kk z-~|J2fwi7}e~=<;gHX~h&Bq{l=sS!vZ}4=IiA%qvZx5Q$o+d-7s)M!=?FKdSM6htS zZ;^zAmW1!@IVQ#GJU%$L3}p~ID&*SZ2SlaTQvm)gkdfxbJC06P`T+!=uN&`$<(nPvpgFZTxj!q z7if*zQ;|tG(+lp4a6EiGQLJjC$zluOc^IKou*xt@9`~t^n==G%ul4vAyhpWl=xg!rwuoS!|&xEXGm@z5Q zV3&;;dx^ykk&D!NR6g_er&Z86#~vX%8f#7Tc~CpYqUc4*J{u#`h5PMB8g{OO@~q>j zy6Q6IMqh0iaSVG4^t!y}^5T_XZ~U!Ru+ixoZEv%!acnoT zt8|$g&N)cDgR0lr%Gg&Do4X4cxAn@M9*-w9U{vj&4^mqNhwW;>#*3b&)d!R9OeHl2 z{t!;B8bPhFvLfR(1$#^+ARv2OUnP`xPBj%-sN^IFNo#N?UPJfD_Dyx_^S5R2E@F>>#FSt z^7dYTsLn`2Tnv0)$=nNh6OeVQgB2;>kd>gxNf%qlW35aT*ZfDPY!s0yw|4^2pbr_ATfI?rzeeE9V;iD&7W`w z(8>K0R%R(Gwp*e536guS=Z;~G8FgM$F3~*>Je-xKt+K@5P?aikr__J?ms))v3khVl za2d1WOI{E6P6_qpBFCZyjVG07k8%P~0y+01tJTEC3B@CC?HK6|+Kd6|V}dxW&ZHSp z`fjQu0`hgYy7Bu$*nk{qnYCT+Rv*tsrYCWjH0n|Pl!hakP2bELsWj>h8&*Zj7^Qrc z`lqYs=>3f^q#1`{iH7>0*}=XnJKcZtD*9dNGmG)u<*oC(cpEX(HIMdw{WK$3vrS|KQ$#qpERG9@eVof?v#)Kdmj_tS)1Ky%YZL`t2TD5*NoF8dr6r=kRKf__Z z=aLf}l&SLv_KNkpu4J9n#g~0o5vL)T;1EZ{SP#1XncNg9P!v~RcQPcPW};8MUYc!*>OS%qw{VtgE*^4`USjC%rgFWvH&C&rsUW!^FX5xuD($clixf}Cj>wP&jS*M|f z>dDEI4JP;W0LuxAF7<4_moUdxX6Ho>BSXFKlr<#NIpqafHX{v7 zQr`4igmyhr2rx-PfjK<+xhe^hQB#owd3>FI^oiI#rt+i70tQUZje!QqM~f{8f?*d6 zn7&fiWIL|Zl9fn2dhvT*Zp2_1=vTPEan0(=EIgq!uP%)OTUx)6aNFUAu@<2M(Slu>aPbf9} zhECnCw(8&-9J;UZV2HyTs869jNdF8DCi&BTSj^T~QeP9H2V@%sTSGelH#R5U6BG~0 zH^wfQ;hhgG7j5%G3~M8N`BFdhQ}J&T1PWRukoxQpo&&BNIxzIW3!@c3u z>|wR^5@vyq#01v_gijq&u6w!f#CL0S{UBU~^ddZh+3F8BLFhk1 zcj#t(PuYjXaSfyeSg#d==NbIz%F)9+t6^cT{cUVaTqX(agN_vMh7CDB)#KT->=C`i2;t|*hR-363oK-!M>XI+9oDYhEv~V zl5Qnnf>BMHB7s`6uey)9yc>TZKCk;c>rO&|fGP1a?{Uxqbp=;6#FExrTudDr|2{6o z7S8YH*xCgxL!^h9=Ub_HD$t z;nWV_kwO5bO79gPe~!`nn1n*gb_^O59NcgO63F?-WgJrbA~iA!fNdWF$7u?dU2sxJ zMs(guMMtu?kU)t(usb4>MfNRHit<-%VEgxi*}cSdi8u_bywtHb5&fYz*U%)O7D9^V zw9TqXjRu3f0(CpR+i26zPaE}7?a&fb8!9%65sKH;R$M%0eQo6SX9=#xcmS$ol-or3x8sZVm5p? z*UAb&IuvD6Ws}QpZNms5VAII%40z{xB*Sf%7H?BZD6CY|)ms=Htk;;pZiSYr6z0w9 zq?@GEo-_d0v{)wGQ{HEF>DtnqeBSD^)Y%rpWO;z!xd|vfGQEthmtY?>7MDr18LE~K31PlE1TAE`_C2C94EVAbfm$bIl;3%-K- zS;580w3KQ04dS>6W|l`=yevv?lTIgd%`?*y$nGOOxw8JRS<4s?n;GR zW^@ph{02!9Ig*on5k&lqUvmn6-TcpB5#Y^gmdL!IZz8zy@se*VXUdQRgeHJ6^+Rm= z#!}1_@_~3Ubwry!HNPL_`3DX{7h47PXnCvUgxdyR@=QpKi~{AU3Qel&5;d8Iu+(Pa z@u_6>mry$B^xJZYr*Q;ttuGu|zKP$q_G|t>tX*|jpF6U~-L(|A;#P_~#i0~;cZ$2a zyF+m;P^4(_;_mM5?ymR8?&3+>W8FZJSG`$ zA3$fm`KVa99Ft#Pp4Vs7@$fvtMH*;&IO7o6g)ui3GC8^r+c!@j9^-I1S&wgKrFTUb zVq(T*eS|`WC3L^%;rbjiw-8ZxRYjKziTWl3G1j1R>nqNZVdX}7SwlcyILqK`$`Pro-T0#M+i|>+uE<&0 zCC-6v43bgIp#vdPV@lr)H5!ni!{UpLKbY-+bf(7huf8Vr3LCGRqFu?!h7!)CRX3n& zg0$cT_!4Oja9g9^Cm?+UwnQ-2tnKl{V>Dv{QQ?iQOgfl!RH>E4#&XyzcqIuX{0TO5 zDwI+^yQp7P+cC5bu~jv<^qH2MmC$h@bWPzy<3f@L;>$s0Kj4~b5QEteB{bMJ>`%V6 zImHyvC@o5bavPXV6tVe8@3zoyXqX|F7GBjY5f-D7%b`BkNl~cqg?E>*cQsg^@121j zEL^~uT(WYxzXAJPyIOcp)iw}&C|O`?69N4;d$kWjGVQlv2>5L5jEA~pgv{Ceqiu3vg%WCKsN@q{Jk7%4oSHz z58kpUx`_V&Y0XiNjM+k@^$j1#lZu;{*JOz(eBR zyPpnfyz`!ULj>?ADgbZt)PH#o{f}dMas%eGywCYXg}AkQE{wDaEuUCJkjt1T*i>mT&45JM0O++K{R=c&G@`x)dVUw`Or%YuZAU4HmyujTx;j7? zPr;*SrL5|Fh=>|od-+*x=lIBoDiv>g32G&>;g8>4NUs4xji7&s|9 zI}C@n!RbM)5jy-DT8j2=IoSN#66oYc1s2f_t))}?f((sm?($=B5y1z<&31j%XciW} zRPBL?w?~aZ+<<~-NXD|#EoR4J%R}xADikQHDORKcA_~HaCd7iROZ- zE#84Z$Rj@|1y)te+I3G+Cm;)J>*mi@GuqDrl~kAEE*{rGR+P)ZO4W#=OWwGBT_aPP z@^0pZ&}^wZcGnlo78RBGX7UiGQ0)!Ex=5r~NJyQ0Nhh%e-YZg`r6RUbQ}TNyulv=_ z%6y@poL+2=`)Ry@P78C5TZw&T`NVt7E2zR2=7PZKRM(<}U5^N}!Jsn%soXJ9F~OP( zqvbovS}bQ`WNBkP>v`r+0S!J8{jIZ+^$Kt~;>%KbT6u@Hh@+kVl>6R{dNQ&q1^<~) zRn=3CEBFLl-8+bYnfxwkEUcumvJx!xHfn~`UPYJNDlDlJ|CkAse5ztKAM(ymGK#9z zHomaQf?+WuAv#dwh0@yJ0`s!tWtXs5KXICU#;g0pW@zF^8E8JnoZt8keR99eJ{al_ zO7Ly53Nh9RmX!&i{FtKVMJeAA_K=CxH>ER5%CE_ce3ne1Ff1zXT9+Ngg>P<^I;p2X z=_U0#au?@qFgOR+UI=qT-OADPLGopssqu=aE=bm)AUGCwn%~lH;w8@CAedt=`kf$^ z2&_-pAvp3+`QhbznvL%mkn*oB(C+R-J>VlEzZd9^Zb-cSc;;C6Hn3UzE{$mNr*AnV zrjFhifJ3o`m_R@@zcJQqOrCekloo>LgwPtNWZ@cvz*I&mrGoiLjYZ~=L_n>cuYi9A zBp+9OJzAs1PgoCqo|Rd3-YJjqoFS^_`lz`hkaA zIo)sHyrSL#~4z>xt4~`Gr!OY;YkOWhAtBT;7(~`ozp#&nn@Y8;n#) z%6Fe}9b$L{K4kQw2MWDcy=r8=-EO=30#O_~S;!qRNpU4-#OBZ`@CZXRv#jQKY$tuF7{?g)R@P2+s*zOWzwT{P%w~NYY#R9h$-1{HYyi^7E`dcRiD4S zAa5*M&Q{EteXaLit;tBTIezOx9PCNMYFHNO9!;TSOUD63XZ{nA&0$dJyAB##V`X#k zH$xHZq~i)yg;^8}=Lf*RT&U8Hy-G=B13im+WHZk1t}K zL6J>gh-X&pU&s}N4}8e|wDQsTz%GcXiqyqfEOg{B)-$QCFWC^>JfZ?t&8H)n4Rfv= z-6k6krN_BQ;v*j+r~!WBv0X&)&8%F*gudViZED(44u7Jv3MJ?sEIs9MMQ=l*YfaF7@E#&oP4Nq<$XZb0$aR**eJ;6Jd5pik)#9_}w@$tnwLkQ@6^B7X!Re2DvG;hTy z)hvo0im*1%Zrtmr;3F*_wb(CHtV6CWDHs_!@4%v+6f~oR0S$5S;>4gDl3uxzk5o4| z;e)uJ_=+5tdl1fn>4dw2VLP5Ayu`kpHIO7vpBY*40i2@-&JJIh8@sHR@#UEg+H79= zHjvl-W(IN`q)0o!Ppp^9n5)BHqB3_lgd3||kk2I+>_wDJ4 zTu!7RN%ZsZ=#*-4c&`_4`ilo@6-*ONJ!7OAe^AlP*G!ghP`eMs!+M>&jzN>Hr1HtO znaA-D5_2puFRd2jC)by?TZ=}tTsTE$F&9OlAvO^)6paNR?2n=5lCk6X)On^EC_kFb zBIBf{7e#9&UU?!MMFL5T&7>LgUpOd+3aLcH!A^xP$6D6L)0u&g<}-O`--%Po7n_dS zBSprRW6byljg-U**Qw~%uA)SQWNI~yLzU4j!>=+IGhxl@&m8GdcP7NKft9MD%spse zL{86a3w8vm<7#|To;SES2E$7xzB`l(K1iI=B2boac8DZI>3e@BB_K%6-3naMnN(jn z(m`L~0;LN)VIdi+Qbj6SW9AYKaf)P7c=)Y*4;fpg%Z=5(To*2sRWjq7V9Yu&7+K$f z@0lNz$Tc0J8cHR*cqjcmnxi4RJ(DLc(c?Zgqbu!}WR!_jgD}Xnv)8Ljb37D{tw+$1_#20{%b3Bx+-oG6B$k-F2w*j~V_PbsMt3B*hVDiag1#Ng|q zmh1JHSCtR|JY2n*cn<@{9C>HM`Pp#GP_)b zsC&lON8iWF0XwTmDX_xRB4@4Az{N1pK#8#iUpUWG_Y+LT>P>^}UP0uoPQxVm>C0Hj ze8q@m{HAs9PbeV5-k2AW?%E_5WkrNz7?j1VGNfJy%&t8LB7A5q8wFP1xW;L0kj@Wml7yV&q}#0TF%?s8Y%a)k`-_ps8CROsol|tckp%q$r=go9tnEUtYB}e zMFIFrLGO+a9cv`2ciY=@$ZNdG$TInnI)+)y75W;fYzHqynqCWrO$+r6N<@SQLs=pA z&E%C71}3@OI5q`LUmSvcHeV5nHiiIE ztUmeR1Xry7siOFkpow4Jgl?&JZ*S@rB2#EvbX?j8?+np_^q301uY$?^kiE=CduUhK z60V_$Mju`xRvPse)j41kx6tJ7^YT3e23j!T`GW>DH-7`3e_ShfQ|f_vFcjUPTwC+)8oKDir7WOe$KFj6a1)d(X;~BsVIilTQ7?&tF+iu+ zbyrWBtwz;SmkXCUTdQ5*pVU=-*uu)~=Z-`Yp=$>CNJTyFm&N5Z`ilEHMAIX(eCIlcq6J!_mUyT^#U?JV~fy!5bIncLpMGJ;X%Z^dJ!h_dCx#Ay8ME1IDy z821vDBlk4H2$bR}V$gzu(G!sc#Yss&i%p<3!-%VCYG0zCgY*!utJN7go5S+j6S3(_ zgYRG3rgOX9rW~o&K`Isxn|{nRZqU8)I;cI%Qc1*h88cNr%QBlx*fTKev8Gvq<7#5Z za7Zfdmow=6Vy8kgb~G3gQcyBeb+Q&*s~4oFroUf~KJHeJ+p4t|z2zT|{c@__>?28~ zx!)MC{->1%+pfhb_mMI;Dtg*EK2|!3sSAF_%9lb=sXq5>Uk)~2wha$mG^_y0&UDso z1lW%aGO;8m*qHU@E|s=sZ8pQePo1ge>OPI0+Hm32Yv~M~xK`*J%wZpom09Q|7pvNZ z2vo1Tq}pE^kJ(dq^}R3WnrHIgG*?slpO|@6}P2ZQ51;?d=0HL`n^Nr~bc5~{WwmsH9StnnnN~u|@ONt7s z>SH~SXp>n|Qu0f`84;Rw!6j#a!vhZ8nJwAwIf*sukAG9>8#I=$pQGnHzhTp>m#z#r zFt35@oH%aH(zmZS=6EX@LltcJS$f!o%k@mqE^}AYnK3 zvk}gip6xcg>oG=1Tww^yTPK#db#26gU;)jHM)-@!ZA^UU@5wkxwWgVoIQ$2>uDLuR z>7not1S;PWTa5#KT=KM-hGyjkc@3K*fPS(RarA_7K$foS8f6&{+o;k?L~87})o|oPj;tt803}?VxJ{NH;hA~Yy;AjzIc(c^ z$h1JjWJ1)TZ(r9t$FgPf&gz&J5xnQ7Brm&2}ZD{lJb7+-E=T% z^MhISj<#XSI`N{+cqXDwBdM*=G%Bw;9JL4fDK}2dr;s~V{a$)!Mk`}zk#>=f9XO(? zARi2NeLZ>oKn1Jb8d-U3V}5qiY^8Y#1k;u`zaplKEN{y2Cc(SoNJWxj#RT#-(*Im(z+Hd)G}`XOG02!ox>=gt~dqS8H#@ zb+ti@00kU4!>@vgyBEL1Ougi|V4NUx2U;hEG^Ih2N>v<=?VQT~NdvX4`i=#eOTq&G zFyFSlcg#3*i{X|k6wRY;1p#<`3QmQ@RbO%FjTXvU2&`PY5}N<)%1q^AX^c;^{)s%@ zc%3|K{X2;$C*X=2J{X~g9(3*Mbt|@+_IXUkHFnFMsSz@^flzAYl?wTDM@+%$70tEP<;1ywdhbEKf0tC z@B&kl384`W3)>4Yd|(g{yku`7vcfZ@X4-ROHBU}S35C_II3~ShN)OtWRhOuXFS7a| zf`=Uw_%7+flYf+TdTkplrN{K5#FLg;T3a}DNUnfR-hfO5MwJ-pC8+Xv?z`7^e)fLI z*(mozW>;<%l%3j>y=R}XV1QT3rM8epX}_Sg-m0-nPF(eD zT-cv{P5;8B{Y+b?ALAOkYV0M%iGA~?Gq5!2Tc~JYw;@aDba6tD{2j26N8d?4zc}Mt z{K#@rH1{NC{votZ!Z)kx9jSAXgH`loLx*>liSVDH>@%hWqO3Z@V=*En(~Jv| z2-9@n16*C{M6<9YJsYCCz3^Bq)4uUhI=?vT@zHHD)J6ehF$*$%>gNUa7Fjt$U3KP_ zh|I9>elR23=$7to)jopq3~~xspV^9bgq6(^bEI0|VLQ!iHi~$KCq-^W-Z4H@@Yxp+ z2BA7;933-tdfY<yMYzF6o2JXXyoeTS z22E65YA@cH%q?%Xkq-!F=%C~o)|*9ERTNHi;U-zX9lh4BSz}4pP??XMGGVN|tTtY9 zbak!}9G9PL2ZXJ#{EG6Z83D0U(mxo2-n|CJnId{jD~F~0oTep7iV?GI5GC#INi~-z zc3~gxBqFFl<6vi{<8E5TFW))+Iz1DCjId7!{O+A3jL>%Ied%S!0H>gQy+oQKo<)xM zwGQ>COO+OAJm_l+E2}7XO^>~csYO>m&gGJro>kh3R`88=;MTbJ*Hl>v{qfr58?1NZ zd#cc(Zb}P6A9Nu(8==4G?v5i#jh3`#8%A?N#b3?LMe)Y?< zRWzZ#>!OAL_#;t_r90G8R$=Tr4)n9AvQY>?mw~ zs+`H7zQt#P5bU0b>9a!z!nLV>y-#k$r9-zny+N70i2O>RMPs1W%XL!pA-*YBxv_tj z+_S^TRA4T5A*Kg4VZGTVzQ5!^Rp0r|&c|xZUgjeK2Rr9Y^>Q=oi?Vu&IxXeWq8g?3 zNPTpM&x=ue?gATy52JPJrSouxWaMM+EY7@TU9>b>p0L+&Kx@3I<>=uaT@2XveV3T* zl3En(s-x&|KvqE)pfG}0uoP;{>T~v?Q(SqCreE|#fxIlBa{H8lKq>}5>Cb7ND3EnK zL~Wl6ChwBOEj=~#F&AvU>MV?#NtD>wWL520GhP))vLiy@wrJx~K3x8gdi&U<(47eS z@r1Atd94Ed`pWtPIN7NIgwQBQ4}*yDwR{vOb8`252v%kSnI_s1-1>D!l)KxS{Dtg3H<%q_&#WQsEzkbOE9x(*h)+% zDI%CjYrZ@PRbTm<94AcH1N7eTpl80Vb8nOFkv&{rre?y#xfa1Ae)X`lX(FpgL%$zBHwkPpr_GDRU|WX5>$~bD z0uCAxJZo$52^7wA%NN0=>)Yjlr$rg0l=04Uk{%6>Z)JiSQz)5ns}kx&jvq` zdzj-G8_HZWkp|XG5vL?Sg0)cNFALK+D8MfJ}L{ zilh!kRC>L~0@<#LEUL7uH5@nd1mAFblg_U{Mi*V-C`uupOrdazvnf?vXb%3>X4m|d zIk`o92pT_=2+@1_LI8bJ=c;SAu4Nr? zk}&jQP$a&loH#maWRdL06NXt&omhA6+hCt2iTjYc%@`U+8MH`_k7J2}Gm ziI*L?WXyZz8HbXLWMg}a=_+OT$>1z@cqL}*Eb0#sopHa}3hpB3d!#&(FYPC#D&l)7 zS1~U%SJASnQwF!4G{z^RL{m%D5$CYlbUlc?ZPd~(Ll2IMZzvf6sXrD!kJKWuE3S0XCYdHR#HuRB511J*|h8qoK-)7(}g-hlTxqtFF*DcsQV{K4;opd{N zOP-X4>iM9@dp8$3ww1`JYgNgw?h=N~6Zrf6xwi?7$xSIU_ctjsB>N^7^P8U3b|g~v z=cjIncw(EINt%Fz+!PSUsLO4@ika8(U5u~AC)eQ+;NCR9`}nEZZ|pPC;x2p`#Z5!t zlFq9kJJVC)^hDDU90vAoTm%T zToK1iF&;{VBUBz*C6Q;1-`Nm^%PxeipQSVku_qUkj7yl$t1~GUrO$@Paj>G%IJSO1 z;FzN2vwu|@3|i{y%V3TWRhAXgz*)7tP_u|9R)RwdZU+0@xa~f5< zWgB8_4`60_Wbz2C>3Ekq?J|$?F9%I5H0w_%lS}Tw-lrJ2 zXE7wT$h!B@#00tXD2O`|>k}Oe;Mtj2yeZ$k49?3VI8{;?8$Vjil>kGbp(_O@uSY{O z8x9F_5euNFA2lBfZ@lChwl5LL?yc(Veqah#_Ni(ya@c~KvY~0St&dCYlN7z8v@KCE zI9u4DxW~MIX_(UlM~Nli(pPwoh>!39zkz;xr{NJobz9~qV5om~zZD}#6$kYNQw)~T ziOH?Sqzjb2XbSaV+@%)A>g<+XUPX~o1Y;Y?g2k;LC|+Ykb_KjXOc;d1e(WaRzA1x# zInM<0bi(esyxFMmnxf&e$};%4`ptNhNbAldXos=i<9Q%qv;ZvCtn)&~kVEcT-;nL0 z0Qfts^ldse897U(V}m#0%VAq-LG|k$!+fHrP*6>cZ zEwG&za^J>ZtS`viP;(>gOWPdIL(-Adn2FEqWc;3}OB>G27P{c0HW9FtPa^Z6)BT=|%+V z#twPqVe+&E?T*7+JT{SEHl?nX5UcPuSswkOU}&I`LY{XTiJn1{ z(RIa|pixj@>24jpAges6o&r)2&~!$T$8e0V+m$*InE|>5XigN~*sl zQ+rcu>y5Fl%0my9Wk38|+&r+c=!AdGUH-g%374dbs0P@!R0TX_e`)(tQAAKs0=$I* z29O{Md{{kicpBj~bS9Xq*Kl!cbU&?Yl4q1RHDayX(wu!pFN{Ti@g@U&CGQGpKO>6( zPg@al<3PllycJ1{ib%s4MThaVWVQw$?u~?-hF8+EA|oN&|8h$Axq%dqE3W{NPk@jB z&%b<#`IG%sTMJ7~Q+<1VQ(9X`Tk-b;;xuB^J#?>w-%}0rtbhRh^E=NoJeQ`VF)un0 zkQLxYDEVKKUq*^PR~6lh>y}ouBoxt6BrI^zo&uuY?>#KPV5Q(H za9pwJhT$#fRA)C9+@5Jp7|W2U)4##pPwy(fk2u=0N0+kMb-VlQHk<75K*Nae<;H4XP(SKl^n)FY@ZmYfO2YM zyhG;~AyL$6wyF-n`P0itr{>elf#u|mFOL_2b)y!0l*+It-}*%ZHwYe5GRIR$ujHb= zqD7S&wh}cLLGfJ*nNTba>?LK;+E|i#e+x`UiC2c=g<<3kvB6Oy}%va32lWBJ*Z~9 zL87`uC*7&bb&2;AG8eoJUJR-*xU1}=0VErZ^5I7S53|~IflQ^E3GsZh4bj$I()lF7 zpTP9gCFZ^+Y&$Up6$_akbet_V74CV63?m&O`7h?Gs)+bC3tzduPbP z^lz?mnE7lZ_LIrsX^9;87Vlgv>cQi2Nxa4QE2f(@4@Y#jw`f)~OfSG57r3s3apgXG zfplVn-&zN3@XvH@-Et0~Rw1&RfO;(_td&^sj84}(^*cN|vT0N)3ab*KwMd#T%Y0F; zIwj>{wKW1YTz=C&2Y-t~((9dh<->kCl~*U(`}lOo@Wf#{PTCU5xyUmo)wdT!qmBYc zLm9s+l_aoVXN`^h%EnFwX{~v}*Pl9&(i92mMuvvlE3fA`-t_Hkzh<-o1+fafjHN-U zvNWmQF(MauFJyUxp-h}rX_UFvJyX;p{Ec!l*wE-zRBf_)7PX(s{2e3=c%I+ME-W)5 zs1%$=@)(A*7|RQgHoDB@0+sY9!jnf&H_YA0;*t~8s1i0QeQY%_EOYPCc7t+tcWuZP zOI2mBaQLjM2W@iaf|+Kp>rY1yz-GJnW$XB=Td1eW)E;*eHkBh^DdUA4l zsgs-$dh|NyjZ=qpT3=z%vh#gO3U$XC=3eP?N)YhjvEM+Q!#c8Fg>6VVp6l$fmJoqi z@VtU3B4C$`0j8Fo;gE)%HiV&_@73mMJyyT?9S8UzZ zqpaMiGUbzbw@HH(M3*3Ucq&VHw3pP|udar^JPnEvWl;O`)HeeW`va#Ez1O8{nOrVh z8P?(zjKSqM?tlQ-w0Yq9ESiFdPp=#oXQ5bHCSOtdVXA3P*NGC+zUPaK68JU25mYEA zFi4pJ^tg%p4%r!D-|HiuRWZ}G{Ro!2(0*9b!ZB0yHxRF=@w61!ZffBxur|}q`IniY zL}fhs-6HnGzH*(I0PN`}ls6bQ+X(vY#*3{+#+KVaX<`r|F8;X;|+?A8K zKAPb2gg*73HfAe4Ts}FwdWXHEd96*P&H8q?j>&l{yCofi`w%;bAK0D^zrr`t6(oc#kNAAHp{WVw3|1WDCunF$n)*o|Ug_ zkeo-(RFN@Va(8cqre@t(f(M-vR)D{8%tKu{+ay!%$xml^7OrJ!pe!KeJcTYddg0C0 zaC2JS*RKbUOp>dSB9}A@RO^GNG^VSs8Q67RjL0)M(uO|@dKB%D8s3LGFY;X0L@p0} zhN9qv2D4AC=&Mbg0JX2*rAWnU^jlN6=VEBx*$_BqnGAr2wPYTC-2FPA*|)+=3@^nP zfKoWVqh(x(AshtV5iUaMRKYhqMYM+$+hN1BQO(D)F1-lxB$s)1#Yi5b<*YdJYAsV~ zE%2pfHk~ms|2PWgSu6y6P308>=sS}HHsVojWm!01S82B=^Os8tZs=bQkC7o4W|W98!80Xx2d4A^zG%;lX>I1!zqp7P$9Vd{E|2OlI%yOQS5KAXzOq$sCQ~n= z;-hMDRGactF??*&DNJcguzKrGA86OUvfZxpZavEngCTCg!j8)c zH=B7~9C~x~o&YZ!n-E=Zh{=V5&FZBRE*dgd``dP2yRXTF>8uL-@pHVIUFC-B zY;+#7M-^&s38TV492izOfE0d$R3#t04HX@zlr5>uhD6rNB)qlE)vWvCP-MZg)GOQX zlotB=Y#wL3Qyv%+=u3?>u)|AzBEH3Bk;PV(cVzBmUdMExJ&fnV;g14)3Kp?}A0s3b zYqY+_C9lGIl@S)jzc|8JW#eC6mU&@N*0Nkeyd}))@$i!G?D34pTd2?h5C2G07Y<;mqqyAt%47U>?*4QM1!#y5~_{ znX@;amcSx^omk;cmulUZT8*r=4=RDV!_c)4B`@<3imP?KqNkx4yFPCl^pvO#*0v7h zBFF67RXdgkx)nZHhyFQIUy$dec#vttK)(-3<13i%J${^k%+KkpHNn1=LSh(_nq{wx z5pxF8$P=rg4m#LBd3y;{NVG;OWthMTYQlf8cmba?YarGcX12l+5vbQvi`ep;AyG?xQ-#iUk4Fa;@a3_u zPhUND-qGI{e0C=goMEKCpjOD+$lvD=FRob?XrI~l%}n_O`4Y|7sNPFcbGu}XlE-w_ zuuq)g+CI=opnpYgdje|NtgUooBYc=F+1j4i#RSRRcd}T?OA~*|mG^#y%k7148sm-Z zgdNO&951&3XjPx~E*MO-@Qq~FD(_Uj+JZr5S$3n~qT<0Z$BpXHc}f2Ds}*ljc)eLOD``+fn91%b*0itLn+)IkWH(^FI3EB*_j!s&|Nr zG{QP7a{{%%P<IC=$v5lny7>$%b zlTTfc;ne-278*1iUf#VezHOfQOzk@AX{N)=g;?)&IXk_yAd(e@>ZZQhC;32g zVrG=vRhD&VG=Qs5XiWLKR%qAKf$KC0w+d?IZIlMWyJ3}CGasU1e3hZ2=@M~hJt;HE zujm3?c;+W;Ut7Ehhm-fJ$|K+9Fl;Ylos+vS3L}O%GbOsE4UoMw@CG;`5?hn((ULhv zoz*EV4lr-2yT+{czu8W9?m``N-fB*t0wQ8EGAC1bZg`~}1ywk{ocv(M8K*n^si5~# zmg18rEJ9a*oj`=Vha1x-eGl|X)8(HTl13(d8L(T+QnN&T!j*SXWgR{g>(C_d#d!)GN=r51_%`A9 zx<{UYj5tj*E90960cX(h_XOI$%RP^Jg+@0*xQP&S3dRqPXl}W?p|f-2xL2&c)#*Dn zj~*$oVhI<>)qg?XdmYpDVWt&kXT90GFb2cQxxFo6Y=0^8y)!s>wYl^o?NF{Z@7R~C zS@M8cx7XmrO|S+_jk4-?K!U(fE2k?m!;0TF8Eet;hX7`MA-Zf#MwfEIrxgq9(d}WhEdzh!3ZO;>8wGYeDX2HYgtvRzBkn0ad zceH%x$+x@rWf5_Fu3m{O*rwn`-C@Suit9!gm+t(BYjZVJ>n3ujEnw;PFzQ37LjBd@ z!qz*54fl++jI8`*&r7ZdiEySi^zn9Q8Havp26&JrbCr`9gjbOfvO1Td;f z3`2kmqqVu>mx(h z^amdi+Eo&a;uXX_kJ^tn9S6x19o(1!s!nWp4NjOx%b=6<`rLiMecr`V2xd*pMz0fX zFtY9M-QUHPDyr|^)ib9TE2%7B$5RIl`jv@09HNw)&V{&qUQ&om#P}+fhapz_g|dhi z*Ja{Ox`lzOKXddrZeUNwml3$^I&4B69BJ-)1#C<zIA4r3`>Q!(an}hIk9xFI ztopMtfu*ag=trsp_C$@~+RRAa3?oMh%`+_oy|wSRuSMv|*KFRfRyHpO=?j?3yaT zxX_`Oy@>QhaoNpP)@u(*QQEB5dL(1M?AX<9)FD-?dhZfQEZkNQ;{(KYWsE&}mO2-w z;?mmkKm@d!jpV`>bz}Em(fGjDZy9XSOam-~i9|tB(SkN3dqTR=->_y`NycumMS*nYO*?W9G8# z#na2uDH;95D8}f^FXND2y(x$F)zTXWt_qKIyRUwMN%wBk_uBK4~v8 z#t2bZ(m=~3D`fDEq|C10V>hSsAl=?+gl-GVK>jXR2o@;*1}$7%)GC{Fh4ckAaxH_y za_bNoXfy1+20NlxRtfu;tLn%iKGyX@ zVaF0^zzg&ApRH9@X}%lV7;K9%*A*Az zBmOIvi3^g$Zk51HFu=CdxG(VR${jAglB!1^nFwybTpyZpz6Db3Z5zCsj=Q54UqmWq zs3~$xj#JXsBhZYa8<)6EyZXg~o8hs1&}V38l1bL{a@lJ;jy1C&hBTa&)_2TOwd-J} zSNV`vFPxMvVs);~-WVR+sU)*{ z>%48I?N^l3iO`G0OT47gKy@kt@6@1K(*@i4G6(|cNqsiZ(2&{GVag2qs4%>F0)m@@ zS8l^Z3f_`S*`(t6Bl0Z*r}M<#Nx+|w3>z&+E}~ee1IZ}JF03lhUF3t8FfXN~pOo!$ z%5xWKX@XHqss`Am4`nx1oGn+p{OpL%qF^M-p>;`F&5%C2G6mir3dQBhoG~VmEAT)o z_wG7=s5rNOC3fU4iIsyq=%Ob70Xvq3{{EtA{oeO}vMpG&1B2^$wid)jd$*CHlD=gK z+GLjV$>x~pm zP!>2Y;CVDdzv_!!eKYZNojekdd(o#S*6V?Ic3e?I^5p<+5|cj+)338QZPihsx)V>4 z^f>gzeGRI5P{sKsGPh>N3!Lni`vzwvPk=bFz#wR#fOE4zP(ZPc)GB~qfB;dD{#LO6 zsGqBx=ct50|J?1>G_W%@rPI_jHaE7_)C8Qg{~72DIAlBp;NX5SAj%)c^Z)))a=e}c zvi=ODV`2Lf1}9)sIMYSFpak&O`+x`MkN7gL@P9z^0$fi28OhYb&`{r6(?;Lc&hi&vYYT%}xPZ&0Iz&J~SU-Smg8y$Y zOKm{F1MQz+o~7fN#zdF{Y^R5r0|5b${!wzg*b)9WjI}->q|V>+3)>o5=>06?ju*9x zZJ%A31pp-i@I0S@{$6st0N1|1pNH1AG}g4R)Hm0B{)JJKUQ^f97!cq0-)Zs)fGZ-! zA{q|pepnXZzirL`6Bmx)KjQu!{wL|5Q3W_~T&@7!b@j*1!GEGIbN)qCfP$>;e}aDQ zh$A_YkFNmAeg#nW^S6ZWCC7{C?SF*Ux3;#h{<(Xf8@wqn9(wbit(ux!vFV!uu$}bv z|I{2)41l-V05a+SFLM<8@S7~p{r8>o7ri$pN&(^yP*)f1-_v@27bwTe5a2-k-OKpf zs{X6x{dwm7j%`EtuS~x;ka=zX64f7>1OBw<4%ZyR?E$k>E8@@cB>X1H9|QRh(qD94 z)fKM?IH2nk0bTd(eSR-FUPey8Cy%}!z}@}#L|fg~7FqzA7yvTyd}jgFIbNM^zen_} zB2&OswLc+Sj+(vw1~5Hofa$USK<4A~`(*!KsAuT!14-Zqo{s^4iRXK$HXBV_i|_LM zscC3-EM|xR^koUqm)sAG_x~40J$+Msz~cOeq<~Dfe~%#ds}WG+jAXM8Xu&?<+A(0Q z{71?0stWx-$o#C;zd}Esm#?V}peF&W2QvR4f3_p&=>G$~rNuuD>QBXgru?q*ALq_l zKpK(1FxOb?n;Dzy0g{RR*{WwGzXUo3ka7;t$v+Ou*9pJL@_jAW{##&?KU>M4WBYzD zIbJ#`e~IYt@yPy6mb+XIZF0b1RDlEn`qB5P{w)fCjs7!S>d$gGgqMOU0!TCf3+Rs| zZ!&&Ij%PFcyGXy7EK&R>ExG_CL4axHN0R02-y!*DjPqZRJZs>)fiZqp2cXXJy3hMd zB+vOo|4bi~S;r<104aO`QoR0w;C=pICwT6tzXyi;Srr>!zH~SNZ1>q?`%!?DqTj~< z)eMAL|8~C!Kp+kn96x%W24%lb@DIo0S5(j4^IaJdKlGJZ)nBACHTl=qE=@~qYg=Po zW6S5=m_O4Jg%Fo~4nRw?02fs92j-do4`x$+ZTo-wGUhDhVn+n%;48o)qx=K+PTl{5 z)PKyif6u50Soi++viOUUP;9Cnhz)2)H=r2`KQzO;>Hn)4&x7T8?frLc*k<=cMt!z5 zzyVB#AKHN2{vX?5W&xP9{#48HZ)FRG0PunUQ~q%*+I0U_cpYtzzhJxA_ZU*@4gcN>Kw0>ssD;YQ}<`dG>vWb&3-|>Tq4|>3!qv7Jc>V1o6Y@y zQfumI+iHJLQ1kQTnm>S>5egtL0XzafG$L^RziWiCxjjJOf4}I(m?Fo<0hjlb9*8O1;AWo3fP$cQ6`<8-{Sk8*X0*BfQN*M zc?sZXK>m3?ggg8#4%=V5yL~Yau9<*7dLF|+dT=slzm2bH0&wJiA%x~mN}&gUpaAgv z=)8-Z|2~POwXuaYAj#k_h%_X@2#o-bdr+vKbv_D9&i%YC z3-`ZVt=X%;%%E>zVXd$Ex1ssn)P5mM@v!lREI=4GfG~95B>~hqUN?7tnaa-A*24T3 z;Kmp&)*gUhj4POb-=F`EpW~JI_&=qce@vBC7{~8jp1pAKvI{O- z9s~;ET_@+~cRtwRDnU1-L~K0%SuV~nNqTO5xa<4lXqZuavh)VRw;JeQVGXjRC;M;p zHP;l{?FRaLBZcc-DU2g$3VTAO&)5;XqVUI9t)$vMU}#n2(N-|};r{*+E|^dY`ZA-4WPQx=?$@Dh2HG}LO*p<<5~inKj9T$_&F+05sUXo| zhZ<**WYUm{FArpI#*94~zfcNKm!}2}Bv>QzeCQ93ugjXCYb0V2u395W(L9dPAe`?V z-8KccHVN06p)0|+8kkP9iox!io6)&?Gj_TIlA0l@gkr@$d0#B?NcncQ!^@v@kF2xu z6HJDRzomJu1&Tj_;%rLs-%eRv&=F!OR(!ZJQDHF2?-V63E5;;`!zP5D7v-sk(b_@oaHk8Qfrhp z|9(f;(TRFbhA3t6!GqBR>`n^&stu82;5<(?qBF}9N7sZAqE%sFy-wl*|K2%_kim#p z`5~7T9&hcM8jio012^+mGMk#%o+r!*9prH&Tp4?_ARbM&4T~@xkKKGx*gWsXh<2ah z?wxNd-w(z4bkI~(B5GW7jp3Qf5m5K&^66*5IE-0J?M^M3 zRsGCMq5v(8ss)x|AqE5LP@Konj)AM~`{^a;9k(nC_ds5CSJk@9t7`fCirLJOqbDHD zj$}FwQ_AIGCR4@RSAD)2sv9S8a<SEzWK>FF zsJjDZ-L~=VcModo&dG>%r?5(fs%ON^c&_RzwtnzZpptflj#?``#SG}bWgFF+H4VUA zy-o402A*n=0WLn!HDh+HI$QcVm^;BNpqQH)Wte)*8$Rtc11H4n7}VnJPV^?dmnd$s z1`dZAJSSpL-ckJuoJb88`AkaZ+Sg=o3+Gv8;;zoGnY{&Ze?lCc9h+&Dp&_GghH6ju zR(u6iB|0#V61KrFiBib%jT!Z4-!HWvf;tzmT<7nXrkX5jL*9um%E0o#dD40Ptha<& zjSWpcgEO{{p4W;Nu^qF_K>Lkx{8Gp7=ygV3+K{u>ft^=jj`FB6e6ch9HA&~ zFE82qU148o7p(q-550A@ACa_flD6FR*s`cH=oml>>p4ottTbuK-8fsIUT3L+Pda5K z5zvxpX0~2DLB7`|iX?~8M!_>%$eU0~yDd;mrVd+en9v^Y5v46IvC4@I*}AO+vE_sn zgz@1CTfmW!K2k+Vx_jaXVN1vn^R1^v&4;{$cB?s9P>$Wour;FyW9Bna2LGY}TOo&7 z-u0!pWo{CLt&KoT4}BwSnwJ#U9^_%)Qzyo+p9vc$|8c_bb@jz9&3ovG*zFq=u^W8$ zh&9SSPDG5leiJcDJypaSXP+k0jSmL;gp4mdR8(9L1vhE4`SG_3JGCcn*zvFb0h|4y Aj{pDw From c5f0138361b822224fcd8ee2da9d487b4d715c9e Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Mon, 13 Jan 2025 22:59:32 +0300 Subject: [PATCH 272/296] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 272d8fc..8e4982a 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,11 @@ _src/generator1/_ #### 🛠️ client_generator.log - Автоматически генерируемый файл (появляется после запуска тестового скрипта) -- Логгирует асинхронные методы, отражает работу методов +- Логгирует асинхронные методы, отражает работу генерации методов #### 🛠️ pachca_testresults.log - Автоматически генерируемый файл (появляется после запуска тестового скрипта) -- Логгирует тестовые функции, отражает полученные данные в тестах +- Логгирует тестовые функции, отражает полученные данные в тест-запросах --- @@ -380,4 +380,4 @@ _src/builder/_ **📄 Документация API**: [Pachca API Documentation](https://crm.pachca.com/dev/getting-started/requests-and-responses/) ---- \ No newline at end of file +--- From 8336695709dd21574c04721c5606af35c4f124ca Mon Sep 17 00:00:00 2001 From: Alex <143039459+shft1@users.noreply.github.com> Date: Mon, 13 Jan 2025 23:06:01 +0300 Subject: [PATCH 273/296] Update README.md --- src/generator1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generator1/README.md b/src/generator1/README.md index 0f3cd4d..5f6070b 100644 --- a/src/generator1/README.md +++ b/src/generator1/README.md @@ -3,7 +3,7 @@ Инструкция (работать в папке generator1): 1. В venv прописать -pip install openapi-python-client +pip install -r requirements.txt 2. Сгенерировать клиент командой From 182ce58b6cd0ca49f5b9acc3d24e36ca4d986e86 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 14 Jan 2025 01:07:59 +0500 Subject: [PATCH 274/296] final --- .env.example | 3 ++ README.md | 44 ++++++++-------------- src/builder/Makefile | 22 +++++++++-- src/builder/README.md | 56 +++++++++++++++++++++------- src/builder/requirements_builder.txt | 5 +++ src/builder/setup_generator1.py | 17 +++++++-- src/builder/setup_generator2.py | 17 +++++++-- src/generator1/requirements.txt | 1 + 8 files changed, 112 insertions(+), 53 deletions(-) create mode 100644 .env.example create mode 100644 src/builder/requirements_builder.txt diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1cc2142 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +PACKAGE_VERSION=<ВЕРИЯ ПАКЕТА> +TWINE_USERNAME=<ИМЯ> +TWINE_API_TOKEN= \ No newline at end of file diff --git a/README.md b/README.md index 6fe1b1a..3f00b67 100644 --- a/README.md +++ b/README.md @@ -290,53 +290,39 @@ _src/generator2/_ - winget install GnuWin32.Make. -2. **Создание зависимостей для сборки библиотеки:** +2. **Создание зависимостей для работы сборки библиотеки:** ```bash - pip install pipenv - pipenv install requirements.txt + pip install requirements_builder.txt ``` -3. **Создать версию библиотеки при помощи команды (пример):** +3. **Создание зависимостей для библиотеки:** ```bash - export PACKAGE_VERSION='1.1.0' + pipenv install requirements.txt ``` - -4. **Запуск создания библиотеки при помощи команды:** +4. **Запуск создания и загрузки библиотеки на PyPi при помощи команды:** ```bash - make build + make upload ``` -5. **Упакованная библиотека сохраняется в папке repository с указанием метода генерации кода и версии библиотеки (пример):** - - - pachca_generator1-1.1.0-py3-none-any.whl - - pachca_generator2-1.2.1-py3-none-any.whl +5. **Установка бибилотеки с тестового PyPi (копирование ссылки):** -6. **Распаковка бибилотеки:** - - - Для Linux/gitBash: - ```bash - python3 -m venv venv - source venv/scripts/activate - pip install <имя файла>.whl - ``` - - Для Windows cmd: - ```bash - python -m venv venv - .\venv\scripts\activate - pip install <имя файла>.whl - ``` + - pip install -i https://test.pypi.org/simple/ pachca-generator1 + - pip install -i https://test.pypi.org/simple/ pachca-generator2 ## 📂 Структура генератора _src/builder/_ +#### 📜 requirements_builder.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. + #### 📜 requirements.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы над проектом. +- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. #### 📄 Pipfile -- файл, используемый виртуальной средой Pipenv для управления зависимостями проекта. +- файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. #### 🔒 Pipfile.lock - файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. @@ -345,7 +331,7 @@ _src/builder/_ - файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. #### 📦 setup_generator1.py, setup_generator2.py -- файле с описанием, каким именно образом будет упакован код для медотов генерации +- файл с описанием, каким именно образом будет упакован код для медотов генерации --- diff --git a/src/builder/Makefile b/src/builder/Makefile index 98a8ca9..3c88889 100644 --- a/src/builder/Makefile +++ b/src/builder/Makefile @@ -1,14 +1,30 @@ +ifneq (,$(wildcard ../../.env)) + include ../../.env + export +endif + +.PHONY: help help: - @echo "Tasks in \033[1;32mdemo\033[0m:" - @cat Makefile + @echo "Команды:" + @echo " help - Список всех команд" + @echo " test - Запуск тестов" + @echo " build - Создание библиотеки" + @echo " clean - Очистка ременных файлов" + @echo " upload - Загрузка библиотеки на PyPi" test: build: clean - pip install wheel python setup_generator1.py bdist_wheel --dist-dir=../repository/ python setup_generator2.py bdist_wheel --dist-dir=../repository/ clean: @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ + +.PHONY: upload +upload: build + @echo "library пакет" + @echo $$TWINE_USERNAME + @echo $$TWINE_API_TOKEN + TWINE_USERNAME=$$TWINE_USERNAME TWINE_PASSWORD=$$TWINE_API_TOKEN twine upload --repository testpypi ../repository/* --verbose \ No newline at end of file diff --git a/src/builder/README.md b/src/builder/README.md index 7be090f..190e5f6 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -1,22 +1,52 @@ -# Инструменты для генерации библиотеки +# 🔧 ***builder*** +## 🛠️ Инструменты для генерации библиотеки -## Порядок подготоительных действий: +### 📋 Порядок действий (работать в папке `builder` при активированном `venv`): -1. pip install pipenv +1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** -2. pipenv install requirements.txt + - winget install GnuWin32.Make. -- pipenv считал всю инфу с venv и создал файлы зависимостей Pipfile (в том числе lock) +2. **Создание зависимостей для работы сборки библиотеки:** -## Создать версию библиотеки при помощи команды (пример): -- export PACKAGE_VERSION='1.1.0' + ```bash + pip install requirements_builder.txt + ``` -## Запуск создания библиотеки при помощи команды: +3. **Создание зависимостей для библиотеки:** -- make build + ```bash + pipenv install requirements.txt + ``` +4. **Запуск создания и загрузки библиотеки на PyPi при помощи команды:** -## Распаковка бибилотеки (для Windows) -- python -m venv venv -- source venv/Scripts/activate -- pip install <имя файла>.whl + ```bash + make upload + ``` +5. **Установка бибилотеки с тестового PyPi (копирование ссылки):** + + - pip install -i https://test.pypi.org/simple/ pachca-generator1 + - pip install -i https://test.pypi.org/simple/ pachca-generator2 + +## 📂 Структура генератора + +_src/builder/_ + +#### 📜 requirements_builder.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. + +#### 📜 requirements.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. + +#### 📄 Pipfile +- файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. + +#### 🔒 Pipfile.lock +- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. + +#### 🛠️ Makefile +- файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. + +#### 📦 setup_generator1.py, setup_generator2.py +- файл с описанием, каким именно образом будет упакован код для медотов генерации \ No newline at end of file diff --git a/src/builder/requirements_builder.txt b/src/builder/requirements_builder.txt new file mode 100644 index 0000000..1a7acdd --- /dev/null +++ b/src/builder/requirements_builder.txt @@ -0,0 +1,5 @@ +python-dotenv==1.0.1 +pipenv==2024.4.0 +setuptools==75.6.0 +twine==6.0.1 +wheel==0.45.1 \ No newline at end of file diff --git a/src/builder/setup_generator1.py b/src/builder/setup_generator1.py index 33d153a..5c559e0 100644 --- a/src/builder/setup_generator1.py +++ b/src/builder/setup_generator1.py @@ -1,11 +1,19 @@ +from setuptools import setup, find_packages + import json import os +from dotenv import load_dotenv from pathlib import Path -from setuptools import find_packages, setup + +PACKAGE_VERSION = 'Версия из YAML' + +load_dotenv() this_directory = Path(__file__).parent -long_description = (this_directory / "../../README.md").read_text(encoding='utf-8') +long_description = ( + this_directory / "../../README.md" +).read_text(encoding='utf-8') def read_pipenv_dependencies(fname): @@ -21,7 +29,7 @@ def read_pipenv_dependencies(fname): name='pachca_generator1', long_description=long_description, long_description_content_type='text/markdown', - version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), + version=os.getenv('PACKAGE_VERSION', PACKAGE_VERSION), package_dir={'': '../generator1/pachca-api-open-api-3-0-client'}, packages=find_packages( '../generator1/pachca-api-open-api-3-0-client', include=[ @@ -30,5 +38,6 @@ def read_pipenv_dependencies(fname): description='A pachca_api package generator1.', install_requires=[ *read_pipenv_dependencies('Pipfile.lock'), - ] + ], + python_version='>=3.11' ) diff --git a/src/builder/setup_generator2.py b/src/builder/setup_generator2.py index 5d7532b..eef0ecc 100644 --- a/src/builder/setup_generator2.py +++ b/src/builder/setup_generator2.py @@ -1,11 +1,19 @@ +from setuptools import setup, find_packages + import json import os +from dotenv import load_dotenv from pathlib import Path -from setuptools import find_packages, setup + +PACKAGE_VERSION = 'Версия из YAML' + +load_dotenv() this_directory = Path(__file__).parent -long_description = (this_directory / "../../README.md").read_text(encoding='utf-8') +long_description = ( + this_directory / "../../README.md" +).read_text(encoding='utf-8') def read_pipenv_dependencies(fname): @@ -21,7 +29,7 @@ def read_pipenv_dependencies(fname): name='pachca_generator2', long_description=long_description, long_description_content_type='text/markdown', - version=os.getenv('PACKAGE_VERSION', '0.0.dev0'), + version=os.getenv('PACKAGE_VERSION', PACKAGE_VERSION), package_dir={'': '../generator2'}, packages=find_packages( '../generator2', include=[ @@ -30,5 +38,6 @@ def read_pipenv_dependencies(fname): description='A pachca_api package generator2.', install_requires=[ *read_pipenv_dependencies('Pipfile.lock'), - ] + ], + python_version='>=3.11' ) diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index e41286c..1112cd7 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -4,6 +4,7 @@ httpcore==1.0.7 httpx==0.27.2 Jinja2==3.1.4 openapi-python-client==0.22.0 +python-dotenv==1.0.1 PyYAML==6.0.2 ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 From 17847fbbd29c008f2c9458fc171fbe78e11faa07 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 13 Jan 2025 23:59:34 +0300 Subject: [PATCH 275/296] update to PyPI --- src/builder/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder/Makefile b/src/builder/Makefile index 3c88889..dc95cce 100644 --- a/src/builder/Makefile +++ b/src/builder/Makefile @@ -20,7 +20,7 @@ build: clean python setup_generator2.py bdist_wheel --dist-dir=../repository/ clean: - @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ + @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ ../repository/ .PHONY: upload upload: build From c55e980897832b05ac128ee54297f1a7969f158d Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 14 Jan 2025 00:00:06 +0300 Subject: [PATCH 276/296] update to PyPI --- src/generator2/generator2_full/constants.py | 10 + .../models/models_reqBod_createChat.py | 28 + .../models/models_reqBod_createMessage.py | 66 ++ .../models/models_reqBod_createTask.py | 45 ++ .../models/models_reqBod_editMessage.py | 46 ++ .../models/models_reqBod_getDirectUrl.py | 37 + .../models_reqBod_postMembersToChats.py | 14 + .../models_reqBod_postMessageReactions.py | 7 + .../models/models_reqBod_postTagsToChats.py | 10 + .../models/models_reqBod_putStatus.py | 19 + .../models_response_createChatpost201.py | 43 ++ .../models_response_createChatpost400.py | 30 + .../models_response_createChatpost422.py | 30 + .../models_response_createMessagepost201.py | 104 +++ .../models_response_createMessagepost400.py | 30 + .../models_response_createTaskpost201.py | 66 ++ .../models_response_createTaskpost400.py | 30 + .../models_response_createThreadpost200.py | 23 + .../models_response_createThreadpost400.py | 30 + ...esponse_deleteMessageReactionsdelete400.py | 30 + .../models_response_editMessageput200.py | 104 +++ .../models_response_editMessageput400.py | 30 + .../models/models_response_getChatget200.py | 43 ++ .../models/models_response_getChatget400.py | 30 + .../models/models_response_getChatsget200.py | 45 ++ .../models/models_response_getChatsget400.py | 30 + .../models/models_response_getChatsget422.py | 30 + .../models_response_getCommonMethodsget200.py | 23 + .../models_response_getCommonMethodsget400.py | 30 + .../models_response_getEmployeeget200.py | 90 +++ .../models_response_getEmployeeget400.py | 30 + .../models_response_getEmployeesget200.py | 92 +++ .../models_response_getListMessageget200.py | 106 +++ .../models_response_getListMessageget400.py | 30 + ...dels_response_getMessageReactionsget200.py | 20 + ...dels_response_getMessageReactionsget400.py | 30 + .../models_response_getMessageget200.py | 104 +++ .../models_response_getMessageget400.py | 30 + .../models/models_response_getStatusget200.py | 19 + .../models/models_response_getTagget200.py | 18 + .../models/models_response_getTagget400.py | 30 + .../models_response_getTagsEmployeesget200.py | 68 ++ .../models_response_getTagsEmployeesget400.py | 30 + .../models/models_response_getTagsget200.py | 17 + .../models/models_response_getTagsget400.py | 30 + .../models_response_getUploadspost200.py | 39 ++ .../models_response_leaveChatdelete400.py | 30 + ...dels_response_postMembersToChatspost400.py | 30 + ...dels_response_postMembersToChatspost422.py | 30 + ...ls_response_postMessageReactionspost400.py | 30 + .../models_response_postTagsToChatspost400.py | 30 + .../models_response_postTagsToChatspost422.py | 30 + .../models/models_response_putStatusput201.py | 19 + .../models/models_response_putStatusput400.py | 30 + .../generator2_full/request_methods.py | 630 ++++++++++++++++++ src/repository/README.md | 1 - .../pachca_generator1-0.2.2-py3-none-any.whl | Bin 0 -> 128920 bytes .../pachca_generator2-0.2.2-py3-none-any.whl | Bin 0 -> 137447 bytes 58 files changed, 2705 insertions(+), 1 deletion(-) create mode 100644 src/generator2/generator2_full/constants.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_createChat.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_createMessage.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_createTask.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_editMessage.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py create mode 100644 src/generator2/generator2_full/models/models_reqBod_putStatus.py create mode 100644 src/generator2/generator2_full/models/models_response_createChatpost201.py create mode 100644 src/generator2/generator2_full/models/models_response_createChatpost400.py create mode 100644 src/generator2/generator2_full/models/models_response_createChatpost422.py create mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost201.py create mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost400.py create mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost201.py create mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost400.py create mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost200.py create mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost400.py create mode 100644 src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py create mode 100644 src/generator2/generator2_full/models/models_response_editMessageput200.py create mode 100644 src/generator2/generator2_full/models/models_response_editMessageput400.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getChatsget422.py create mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getEmployeesget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getMessageget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getStatusget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsget200.py create mode 100644 src/generator2/generator2_full/models/models_response_getTagsget400.py create mode 100644 src/generator2/generator2_full/models/models_response_getUploadspost200.py create mode 100644 src/generator2/generator2_full/models/models_response_leaveChatdelete400.py create mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py create mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py create mode 100644 src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py create mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py create mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py create mode 100644 src/generator2/generator2_full/models/models_response_putStatusput201.py create mode 100644 src/generator2/generator2_full/models/models_response_putStatusput400.py create mode 100644 src/generator2/generator2_full/request_methods.py delete mode 100644 src/repository/README.md create mode 100644 src/repository/pachca_generator1-0.2.2-py3-none-any.whl create mode 100644 src/repository/pachca_generator2-0.2.2-py3-none-any.whl diff --git a/src/generator2/generator2_full/constants.py b/src/generator2/generator2_full/constants.py new file mode 100644 index 0000000..7055256 --- /dev/null +++ b/src/generator2/generator2_full/constants.py @@ -0,0 +1,10 @@ +# Client constants +URL = 'https://api.pachca.com/api/shared/v1' +PARAM_NAME_SORT = 'sort' +PARAM_NAME_SORT_FIELD = 'sort_field' +TOKEN_TYPE = 'Bearer' + +# Logger constants +LOG_FILE_NAME = 'pachca_log.log' +MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB +BACKUP_COUNT = 3 diff --git a/src/generator2/generator2_full/models/models_reqBod_createChat.py b/src/generator2/generator2_full/models/models_reqBod_createChat.py new file mode 100644 index 0000000..089e9c2 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_createChat.py @@ -0,0 +1,28 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Chat(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + + +class Createchat(BaseModel): + chat: Optional[Chat] = Field( + None, + description="Собранный объект параметров создаваемой беседы или канала", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createMessage.py b/src/generator2/generator2_full/models/models_reqBod_createMessage.py new file mode 100644 index 0000000..a6280ed --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_createMessage.py @@ -0,0 +1,66 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + size: int = Field( + ..., description="Размер файла в байтах, отображаемый пользователю", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Message(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + skip_invite_mentions: Optional[bool] = Field( + None, description="No docstring provided", + ) + link_preview: Optional[bool] = Field( + None, description="No docstring provided", + ) + + +class Createmessage(BaseModel): + message: Optional[Message] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createTask.py b/src/generator2/generator2_full/models/models_reqBod_createTask.py new file mode 100644 index 0000000..ce503e3 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_createTask.py @@ -0,0 +1,45 @@ +from enum import IntEnum, StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + value: Optional[str] = Field(None, description="Значение поля") + + +class enum_kind(StrEnum): + call = "call" + meeting = "meeting" + reminder = "reminder" + event = "event" + email = "email" + + +class enum_priority(IntEnum): + priority_1 = 1 + priority_2 = 2 + priority_3 = 3 + + +class Task(BaseModel): + kind: enum_kind = Field(..., description="Тип напоминания") + content: str = Field(..., description="Описание напоминания") + due_at: str = Field( + ..., description="Срок выполнения напоминания (ISO-8601)", + ) + priority: Optional[enum_priority] = Field( + None, + description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", + ) + performer_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов пользователей", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="No docstring provided", + ) + + +class Createtask(BaseModel): + task: Optional[Task] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_reqBod_editMessage.py b/src/generator2/generator2_full/models/models_reqBod_editMessage.py new file mode 100644 index 0000000..8db9faf --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_editMessage.py @@ -0,0 +1,46 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + size: int = Field( + ..., description="Размер файла в байтах, отображаемый пользователю", + ) + + +class Message(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + + +class Editmessage(BaseModel): + message: Optional[Message] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py new file mode 100644 index 0000000..a4f35e7 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py @@ -0,0 +1,37 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Getdirecturl(BaseModel): + Content_Disposition: Optional[str] = Field( + None, + description="Используемый заголовок", + alilas="Content-Disposition", + ) + acl: Optional[str] = Field(None, description="Уровень безопасности") + policy: Optional[str] = Field( + None, description="Уникальный policy для загрузки файла", + ) + x_amz_credential: Optional[str] = Field( + None, + description="x-amz-credential для загрузки файла", + alilas="x-amz-credential", + ) + x_amz_algorithm: Optional[str] = Field( + None, description="Используемый алгоритм", alilas="x-amz-algorithm", + ) + x_amz_date: Optional[str] = Field( + None, + description="Уникальный x-amz-date для загрузки файла", + alilas="x-amz-date", + ) + x_amz_signature: Optional[str] = Field( + None, + description="Уникальная подпись для загрузки файла", + alilas="x-amz-signature", + ) + key: Optional[str] = Field( + None, description="Уникальный ключ для загрузки файла", + ) + file: Optional[str] = Field(None, description="Адрес для загрузки файла") diff --git a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py new file mode 100644 index 0000000..59b7182 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py @@ -0,0 +1,14 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Postmemberstochats(BaseModel): + member_ids: List[int] = Field( + ..., + description="Массив идентификаторов пользователей, которые станут участниками", + ) + silent: Optional[bool] = Field( + None, + description="Не создавать в чате системное сообщение о добавлении участника", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py new file mode 100644 index 0000000..ba69294 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py @@ -0,0 +1,7 @@ +from pydantic import BaseModel, Field + + +class Postmessagereactions(BaseModel): + code: str = Field( + ..., description="Emoji в строковом формате для добавления реакции.", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py new file mode 100644 index 0000000..f935dd3 --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py @@ -0,0 +1,10 @@ +from typing import List + +from pydantic import BaseModel, Field + + +class Posttagstochats(BaseModel): + group_tag_ids: List[int] = Field( + ..., + description="Массив идентификаторов тегов, которые станут участниками", + ) diff --git a/src/generator2/generator2_full/models/models_reqBod_putStatus.py b/src/generator2/generator2_full/models/models_reqBod_putStatus.py new file mode 100644 index 0000000..0e19d8f --- /dev/null +++ b/src/generator2/generator2_full/models/models_reqBod_putStatus.py @@ -0,0 +1,19 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Status(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class Putstatus(BaseModel): + status: Optional[Status] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost201.py b/src/generator2/generator2_full/models/models_response_createChatpost201.py new file mode 100644 index 0000000..289211b --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createChatpost201.py @@ -0,0 +1,43 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + id: Optional[int] = Field( + None, description="Идентификатор беседы или канала", + ) + owner_id: Optional[int] = Field( + None, + description="Идентификатор пользователя, создавшего беседу или канал", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + last_message_at: Optional[str] = Field( + None, + description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + meet_room_url: Optional[str] = Field( + None, description="Ссылка на Видеочат", + ) + + +class ResponseCreatechatPost201(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createChatpost400.py b/src/generator2/generator2_full/models/models_response_createChatpost400.py new file mode 100644 index 0000000..3d5be37 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createChatpost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatechatPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost422.py b/src/generator2/generator2_full/models/models_response_createChatpost422.py new file mode 100644 index 0000000..9ee79aa --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createChatpost422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatechatPost422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost201.py b/src/generator2/generator2_full/models/models_response_createMessagepost201.py new file mode 100644 index 0000000..a7da269 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createMessagepost201.py @@ -0,0 +1,104 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseCreatemessagePost201(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost400.py b/src/generator2/generator2_full/models/models_response_createMessagepost400.py new file mode 100644 index 0000000..b484245 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createMessagepost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatemessagePost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost201.py b/src/generator2/generator2_full/models/models_response_createTaskpost201.py new file mode 100644 index 0000000..749ca91 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createTaskpost201.py @@ -0,0 +1,66 @@ +from enum import IntEnum, StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + value: Optional[str] = Field(None, description="Значение поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + + +class enum_kind(StrEnum): + call = "call" + meeting = "meeting" + reminder = "reminder" + event = "event" + email = "email" + + +class enum_priority(IntEnum): + priority_1 = 1 + priority_2 = 2 + priority_3 = 3 + + +class Data(BaseModel): + kind: enum_kind = Field(..., description="Тип напоминания") + content: str = Field(..., description="Описание напоминания") + due_at: str = Field( + ..., description="Срок выполнения напоминания (ISO-8601)", + ) + priority: Optional[enum_priority] = Field( + None, + description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", + ) + performer_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов пользователей", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="No docstring provided", + ) + id: Optional[int] = Field( + None, description="Идентификатор созданного напоминания", + ) + user_id: Optional[int] = Field( + None, description="Идентификатор пользователя-создателя", + ) + status: Optional[str] = Field(None, description="Статус напоминания") + created_at: Optional[str] = Field( + None, description="Дата и время создания", + ) + + +class ResponseCreatetaskPost201(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost400.py b/src/generator2/generator2_full/models/models_response_createTaskpost400.py new file mode 100644 index 0000000..7b83d43 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createTaskpost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatetaskPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost200.py b/src/generator2/generator2_full/models/models_response_createThreadpost200.py new file mode 100644 index 0000000..93e2199 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createThreadpost200.py @@ -0,0 +1,23 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред.", + ) + message_chat_id: Optional[int] = Field( + None, description="Идентификатор чата сообщения.", + ) + updated_at: Optional[str] = Field( + None, + description="Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", + ) + + +class ResponseCreatethreadPost200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost400.py b/src/generator2/generator2_full/models/models_response_createThreadpost400.py new file mode 100644 index 0000000..aab3648 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_createThreadpost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseCreatethreadPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py new file mode 100644 index 0000000..c80757d --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseDeletemessagereactionsDelete400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_editMessageput200.py b/src/generator2/generator2_full/models/models_response_editMessageput200.py new file mode 100644 index 0000000..2daa577 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_editMessageput200.py @@ -0,0 +1,104 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseEditmessagePut200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_editMessageput400.py b/src/generator2/generator2_full/models/models_response_editMessageput400.py new file mode 100644 index 0000000..cb7e60d --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_editMessageput400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseEditmessagePut400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatget200.py b/src/generator2/generator2_full/models/models_response_getChatget200.py new file mode 100644 index 0000000..26c9d0a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatget200.py @@ -0,0 +1,43 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + id: Optional[int] = Field( + None, description="Идентификатор беседы или канала", + ) + owner_id: Optional[int] = Field( + None, + description="Идентификатор пользователя, создавшего беседу или канал", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + last_message_at: Optional[str] = Field( + None, + description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + meet_room_url: Optional[str] = Field( + None, description="Ссылка на Видеочат", + ) + + +class ResponseGetchatGet200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getChatget400.py b/src/generator2/generator2_full/models/models_response_getChatget400.py new file mode 100644 index 0000000..5cf12e6 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetchatGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget200.py b/src/generator2/generator2_full/models/models_response_getChatsget200.py new file mode 100644 index 0000000..68c2eec --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatsget200.py @@ -0,0 +1,45 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + name: str = Field(..., description="Название") + member_ids: Optional[List[int]] = Field( + None, + description="Массив идентификаторов пользователей, которые станут участниками", + ) + group_tag_ids: Optional[List[int]] = Field( + None, description="Массив идентификаторов тегов, участников", + ) + channel: Optional[bool] = Field( + None, description="Тип: беседа (по умолчанию, false) или канал (true)", + ) + public: Optional[bool] = Field( + None, + description="Доступ: закрытый (по умолчанию, false) или открытый (true)", + ) + id: Optional[int] = Field( + None, description="Идентификатор беседы или канала", + ) + owner_id: Optional[int] = Field( + None, + description="Идентификатор пользователя, создавшего беседу или канал", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + last_message_at: Optional[str] = Field( + None, + description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + meet_room_url: Optional[str] = Field( + None, description="Ссылка на Видеочат", + ) + + +class ResponseGetchatsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget400.py b/src/generator2/generator2_full/models/models_response_getChatsget400.py new file mode 100644 index 0000000..0893c6b --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetchatsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget422.py b/src/generator2/generator2_full/models/models_response_getChatsget422.py new file mode 100644 index 0000000..89c7937 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getChatsget422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetchatsGet422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py new file mode 100644 index 0000000..9c132b3 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py @@ -0,0 +1,23 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Название поля") + name: Optional[str] = Field(None, description="Идентификатор поля") + data_type: Optional[enum_data_type] = Field(None, description="тип поля") + + +class ResponseGetcommonmethodsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py new file mode 100644 index 0000000..f2ae8ba --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetcommonmethodsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py new file mode 100644 index 0000000..a798652 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py @@ -0,0 +1,90 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + value: Optional[str] = Field(None, description="Значение") + + +class User_status(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class enum_role(StrEnum): + admin = "admin" + user = "user" + multi_guest = "multi_guest" + + +class enum_invite_status(StrEnum): + confirmed = "confirmed" + sent = "sent" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор пользователя") + first_name: Optional[str] = Field(None, description="Имя") + last_name: Optional[str] = Field(None, description="Фамилия") + nickname: Optional[str] = Field(None, description="Имя пользователя") + email: Optional[str] = Field(None, description="Электронная почта") + phone_number: Optional[str] = Field(None, description="Телефон") + department: Optional[str] = Field(None, description="Департамент") + role: Optional[enum_role] = Field( + None, + description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", + ) + suspended: Optional[bool] = Field( + None, + description="Деактивация пользователя. При значении true пользователь является деактивированным.", + ) + invite_status: Optional[enum_invite_status] = Field( + None, + description="Статус приглашения: confirmed (принято), sent (отправлено)", + ) + list_tags: Optional[List[str]] = Field( + None, description="Массив тегов, привязанных к сотруднику", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="Дополнительные поля сотрудника", + ) + bot: Optional[bool] = Field( + None, description="Тип: пользователь (false) или бот (true)", + ) + user_status: Optional[User_status] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) + title: Optional[str] = Field(None, description="Должность") + created_at: Optional[str] = Field( + None, + description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + time_zone: Optional[str] = Field( + None, description="Часовой пояс пользователя", + ) + image_url: Optional[str] = Field( + None, description="Ссылка на скачивание аватарки", + ) + + +class ResponseGetemployeeGet200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py new file mode 100644 index 0000000..a22237a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetemployeeGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py new file mode 100644 index 0000000..6f24174 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py @@ -0,0 +1,92 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + value: Optional[str] = Field(None, description="Значение") + + +class User_status(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class enum_role(StrEnum): + admin = "admin" + user = "user" + multi_guest = "multi_guest" + + +class enum_invite_status(StrEnum): + confirmed = "confirmed" + sent = "sent" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор пользователя") + first_name: Optional[str] = Field(None, description="Имя") + last_name: Optional[str] = Field(None, description="Фамилия") + nickname: Optional[str] = Field(None, description="Имя пользователя") + email: Optional[str] = Field(None, description="Электронная почта") + phone_number: Optional[str] = Field(None, description="Телефон") + department: Optional[str] = Field(None, description="Департамент") + role: Optional[enum_role] = Field( + None, + description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", + ) + suspended: Optional[bool] = Field( + None, + description="Деактивация пользователя. При значении true пользователь является деактивированным.", + ) + invite_status: Optional[enum_invite_status] = Field( + None, + description="Статус приглашения: confirmed (принято), sent (отправлено)", + ) + list_tags: Optional[List[str]] = Field( + None, description="Массив тегов, привязанных к сотруднику", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="Дополнительные поля сотрудника", + ) + bot: Optional[bool] = Field( + None, description="Тип: пользователь (false) или бот (true)", + ) + user_status: Optional[User_status] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) + title: Optional[str] = Field(None, description="Должность") + created_at: Optional[str] = Field( + None, + description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + time_zone: Optional[str] = Field( + None, description="Часовой пояс пользователя", + ) + image_url: Optional[str] = Field( + None, description="Ссылка на скачивание аватарки", + ) + + +class ResponseGetemployeesGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget200.py b/src/generator2/generator2_full/models/models_response_getListMessageget200.py new file mode 100644 index 0000000..c187528 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getListMessageget200.py @@ -0,0 +1,106 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseGetlistmessageGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget400.py b/src/generator2/generator2_full/models/models_response_getListMessageget400.py new file mode 100644 index 0000000..9bc441d --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getListMessageget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetlistmessageGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py new file mode 100644 index 0000000..ce9da6a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py @@ -0,0 +1,20 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + user_id: Optional[int] = Field( + None, description="Идентификатор пользователя, оставившего реакцию.", + ) + created_at: Optional[str] = Field( + None, + description="Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", + ) + code: Optional[str] = Field(None, description="Emoji символ реакции.") + + +class ResponseGetmessagereactionsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py new file mode 100644 index 0000000..369fcdf --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetmessagereactionsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageget200.py b/src/generator2/generator2_full/models/models_response_getMessageget200.py new file mode 100644 index 0000000..92d3d71 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageget200.py @@ -0,0 +1,104 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Buttons(BaseModel): + text: Optional[str] = Field(None, description="No docstring provided") + url: Optional[str] = Field(None, description="No docstring provided") + data: Optional[str] = Field(None, description="No docstring provided") + + +class enum_file_type(StrEnum): + file = "file" + image = "image" + + +class Files(BaseModel): + key: str = Field( + ..., + description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", + ) + name: str = Field( + ..., + description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", + ) + file_type: enum_file_type = Field(..., description="No docstring provided") + id: Optional[int] = Field(None, description="No docstring provided") + url: Optional[str] = Field( + None, description="Прямая временная ссылка на скачивание файла", + ) + + +class Thread(BaseModel): + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + + +class Forwarding(BaseModel): + original_message_id: Optional[int] = Field( + None, description="Идентификатор оригинального сообщения", + ) + original_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + author_id: Optional[int] = Field( + None, + description="Идентификатор чата, в котором находится оригинальное сообщение", + ) + original_created_at: Optional[int] = Field( + None, + description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", + ) + original_thread_id: Optional[int] = Field( + None, + description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + original_thread_parent_chat_id: Optional[int] = Field( + None, + description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", + ) + + +class enum_entity_type(StrEnum): + discussion = "discussion" + user = "user" + thread = "thread" + + +class Data(BaseModel): + content: str = Field(..., description="Текст сообщения") + buttons: Optional[List[List[Buttons]]] = Field( + None, description="No docstring provided", + ) + entity_type: Optional[enum_entity_type] = Field( + None, description="No docstring provided", + ) + entity_id: int = Field(..., description="No docstring provided") + parent_message_id: Optional[int] = Field( + None, + description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", + ) + id: Optional[int] = Field(None, description="No docstring provided") + chat_id: Optional[int] = Field(None, description="No docstring provided") + user_id: Optional[int] = Field(None, description="No docstring provided") + created_at: Optional[str] = Field( + None, description="No docstring provided", + ) + files: Optional[List[Files]] = Field( + None, description="No docstring provided", + ) + thread: Optional[Thread] = Field(None, description="No docstring provided") + forwarding: Optional[Forwarding] = Field( + None, description="No docstring provided", + ) + + +class ResponseGetmessageGet200(BaseModel): + data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getMessageget400.py b/src/generator2/generator2_full/models/models_response_getMessageget400.py new file mode 100644 index 0000000..9c51172 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getMessageget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGetmessageGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getStatusget200.py b/src/generator2/generator2_full/models/models_response_getStatusget200.py new file mode 100644 index 0000000..0d09a11 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getStatusget200.py @@ -0,0 +1,19 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class ResponseGetstatusGet200(BaseModel): + data: Optional[Data] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget200.py b/src/generator2/generator2_full/models/models_response_getTagget200.py new file mode 100644 index 0000000..ef7a650 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagget200.py @@ -0,0 +1,18 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор тега") + name: Optional[str] = Field(None, description="Название тега") + users_count: Optional[int] = Field( + None, description="Количество сотрудников, которые имеют этот тег", + ) + + +class ResponseGettagGet200(BaseModel): + data: Optional[Data] = Field( + None, + description="Для получения тега вам необходимо знать его id и указать его в URL запроса.", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget400.py b/src/generator2/generator2_full/models/models_response_getTagget400.py new file mode 100644 index 0000000..a3b9fe0 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGettagGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py new file mode 100644 index 0000000..d835b3a --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py @@ -0,0 +1,68 @@ +from enum import StrEnum +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class enum_data_type(StrEnum): + string = "string" + number = "number" + date = "date" + link = "link" + + +class Custom_properties(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор поля") + name: Optional[str] = Field(None, description="Название поля") + data_type: Optional[enum_data_type] = Field( + None, description="Тип поля (string, number, date или link)", + ) + value: Optional[str] = Field(None, description="Значение") + + +class enum_role(StrEnum): + admin = "admin" + user = "user" + multi_guest = "multi_guest" + + +class enum_invite_status(StrEnum): + confirmed = "confirmed" + sent = "sent" + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор пользователя") + first_name: Optional[str] = Field(None, description="Имя") + last_name: Optional[str] = Field(None, description="Фамилия") + nickname: Optional[str] = Field(None, description="Имя пользователя") + email: Optional[str] = Field(None, description="Электронная почта") + phone_number: Optional[str] = Field(None, description="Телефон") + department: Optional[str] = Field(None, description="Департамент") + role: Optional[enum_role] = Field( + None, + description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", + ) + suspended: Optional[bool] = Field( + None, + description="Деактивация пользователя. При значении true пользователь является деактивированным.", + ) + invite_status: Optional[enum_invite_status] = Field( + None, + description="Статус приглашения: confirmed (принято), sent (отправлено)", + ) + list_tags: Optional[List[str]] = Field( + None, description="Массив тегов, привязанных к сотруднику", + ) + custom_properties: Optional[List[Custom_properties]] = Field( + None, description="Дополнительные поля сотрудника", + ) + bot: Optional[bool] = Field( + None, description="Тип: пользователь (false) или бот (true)", + ) + + +class ResponseGettagsemployeesGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py new file mode 100644 index 0000000..a7c67de --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGettagsemployeesGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget200.py b/src/generator2/generator2_full/models/models_response_getTagsget200.py new file mode 100644 index 0000000..a6f0b4b --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsget200.py @@ -0,0 +1,17 @@ +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + id: Optional[int] = Field(None, description="Идентификатор тега") + name: Optional[str] = Field(None, description="Название тега") + users_count: Optional[int] = Field( + None, description="Количество сотрудников, которые имеют этот тег", + ) + + +class ResponseGettagsGet200(BaseModel): + data: Optional[List[Data]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget400.py b/src/generator2/generator2_full/models/models_response_getTagsget400.py new file mode 100644 index 0000000..0015a61 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getTagsget400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseGettagsGet400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_getUploadspost200.py b/src/generator2/generator2_full/models/models_response_getUploadspost200.py new file mode 100644 index 0000000..0d31122 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_getUploadspost200.py @@ -0,0 +1,39 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class ResponseGetuploadsPost200(BaseModel): + Content_Disposition: Optional[str] = Field( + None, + description="Используемый заголовок", + alilas="Content-Disposition", + ) + acl: Optional[str] = Field(None, description="Уровень безопасности") + policy: Optional[str] = Field( + None, description="Уникальный policy для загрузки файла", + ) + x_amz_credential: Optional[str] = Field( + None, + description="x-amz-credential для загрузки файла", + alilas="x-amz-credential", + ) + x_amz_algorithm: Optional[str] = Field( + None, description="Используемый алгоритм", alilas="x-amz-algorithm", + ) + x_amz_date: Optional[str] = Field( + None, + description="Уникальный x-amz-date для загрузки файла", + alilas="x-amz-date", + ) + x_amz_signature: Optional[str] = Field( + None, + description="Уникальная подпись для загрузки файла", + alilas="x-amz-signature", + ) + key: Optional[str] = Field( + None, description="Уникальный ключ для загрузки файла", + ) + direct_url: Optional[str] = Field( + None, description="Адрес для загрузки файла", + ) diff --git a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py new file mode 100644 index 0000000..3e430a1 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponseLeavechatDelete400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py new file mode 100644 index 0000000..5dd1dbd --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePostmemberstochatsPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py new file mode 100644 index 0000000..bdf933f --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePostmemberstochatsPost422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py new file mode 100644 index 0000000..0d305f2 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePostmessagereactionsPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py new file mode 100644 index 0000000..e0385a7 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePosttagstochatsPost400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py new file mode 100644 index 0000000..8b157bf --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePosttagstochatsPost422(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput201.py b/src/generator2/generator2_full/models/models_response_putStatusput201.py new file mode 100644 index 0000000..db4d1ca --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_putStatusput201.py @@ -0,0 +1,19 @@ +from typing import Optional + +from pydantic import BaseModel, Field + + +class Data(BaseModel): + emoji: Optional[str] = Field(None, description="Emoji символ статуса") + title: Optional[str] = Field(None, description="Текст статуса") + expires_at: Optional[str] = Field( + None, + description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", + ) + + +class ResponsePutstatusPut201(BaseModel): + data: Optional[Data] = Field( + None, + description="Статус. Возвращается как null, если статус не установлен.", + ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput400.py b/src/generator2/generator2_full/models/models_response_putStatusput400.py new file mode 100644 index 0000000..74a54e1 --- /dev/null +++ b/src/generator2/generator2_full/models/models_response_putStatusput400.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class Errors(BaseModel): + key: Optional[str] = Field( + None, description="Ключ параметра, в котором произошла ошибка", + ) + value: Optional[Any] = Field( + None, description="Значение ключа, которое вызвало ошибку", + ) + message: Optional[str] = Field( + None, + description="Ошибка текстом, который вы можете вывести пользователю", + ) + code: Optional[str] = Field( + None, + description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", + ) + payload: Optional[Dict] = Field( + None, + description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", + ) + + +class ResponsePutstatusPut400(BaseModel): + errors: Optional[List[Errors]] = Field( + None, description="No docstring provided", + ) diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py new file mode 100644 index 0000000..c4bca53 --- /dev/null +++ b/src/generator2/generator2_full/request_methods.py @@ -0,0 +1,630 @@ +from .models.models_reqBod_createChat import Createchat +from .models.models_reqBod_createMessage import Createmessage +from .models.models_reqBod_createTask import Createtask +from .models.models_reqBod_editMessage import Editmessage +from .models.models_reqBod_getDirectUrl import Getdirecturl +from .models.models_reqBod_postMembersToChats import Postmemberstochats +from .models.models_reqBod_postMessageReactions import Postmessagereactions +from .models.models_reqBod_postTagsToChats import Posttagstochats +from .models.models_reqBod_putStatus import Putstatus +from .models.models_response_createChatpost201 import ResponseCreatechatPost201 +from .models.models_response_createChatpost422 import ResponseCreatechatPost422 +from .models.models_response_createMessagepost201 import ( + ResponseCreatemessagePost201, +) +from .models.models_response_createMessagepost400 import ( + ResponseCreatemessagePost400, +) +from .models.models_response_createTaskpost201 import ResponseCreatetaskPost201 +from .models.models_response_createTaskpost400 import ResponseCreatetaskPost400 +from .models.models_response_createThreadpost200 import ( + ResponseCreatethreadPost200, +) +from .models.models_response_createThreadpost400 import ( + ResponseCreatethreadPost400, +) +from .models.models_response_deleteMessageReactionsdelete400 import ( + ResponseDeletemessagereactionsDelete400, +) +from .models.models_response_editMessageput200 import ResponseEditmessagePut200 +from .models.models_response_editMessageput400 import ResponseEditmessagePut400 +from .models.models_response_getChatget200 import ResponseGetchatGet200 +from .models.models_response_getChatget400 import ResponseGetchatGet400 +from .models.models_response_getChatsget200 import ResponseGetchatsGet200 +from .models.models_response_getChatsget422 import ResponseGetchatsGet422 +from .models.models_response_getCommonMethodsget200 import ( + ResponseGetcommonmethodsGet200, +) +from .models.models_response_getCommonMethodsget400 import ( + ResponseGetcommonmethodsGet400, +) +from .models.models_response_getEmployeeget200 import ResponseGetemployeeGet200 +from .models.models_response_getEmployeeget400 import ResponseGetemployeeGet400 +from .models.models_response_getEmployeesget200 import ( + ResponseGetemployeesGet200, +) +from .models.models_response_getListMessageget200 import ( + ResponseGetlistmessageGet200, +) +from .models.models_response_getListMessageget400 import ( + ResponseGetlistmessageGet400, +) +from .models.models_response_getMessageReactionsget200 import ( + ResponseGetmessagereactionsGet200, +) +from .models.models_response_getMessageReactionsget400 import ( + ResponseGetmessagereactionsGet400, +) +from .models.models_response_getMessageget200 import ResponseGetmessageGet200 +from .models.models_response_getMessageget400 import ResponseGetmessageGet400 +from .models.models_response_getStatusget200 import ResponseGetstatusGet200 +from .models.models_response_getTagget200 import ResponseGettagGet200 +from .models.models_response_getTagget400 import ResponseGettagGet400 +from .models.models_response_getTagsEmployeesget200 import ( + ResponseGettagsemployeesGet200, +) +from .models.models_response_getTagsEmployeesget400 import ( + ResponseGettagsemployeesGet400, +) +from .models.models_response_getTagsget200 import ResponseGettagsGet200 +from .models.models_response_getTagsget400 import ResponseGettagsGet400 +from .models.models_response_getUploadspost200 import ResponseGetuploadsPost200 +from .models.models_response_leaveChatdelete400 import ( + ResponseLeavechatDelete400, +) +from .models.models_response_postMembersToChatspost422 import ( + ResponsePostmemberstochatsPost422, +) +from .models.models_response_postMessageReactionspost400 import ( + ResponsePostmessagereactionsPost400, +) +from .models.models_response_postTagsToChatspost422 import ( + ResponsePosttagstochatsPost422, +) +from .models.models_response_putStatusput201 import ResponsePutstatusPut201 +from .models.models_response_putStatusput400 import ResponsePutstatusPut400 + + +class RequestMethods: + + async def get_client(self): + pass + + async def format_url(self): + pass + + async def filter_query_params(self): + pass + + async def get_common_methods( + self, entity_type: str = None, + ) -> ResponseGetcommonmethodsGet200: + """получение списка актульных полей сущности + + Метод для получения актуального списка дополнительных полей участников и + напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в + URL (например, /custom_properties?entity_type=User) + """ + client = await self.get_client() + async with client: + url = "/custom_properties" + query_params = await self.filter_query_params( + entity_type=entity_type, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetcommonmethodsGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetcommonmethodsGet400.model_validate_json( + response.text, + ) + return None + + async def get_uploads(self) -> ResponseGetuploadsPost200: + """получения подписи и ключа для загрузки файла + + Данный метод необходимо использовать для загрузки каждого файла. Данный метод + позволяет получить уникальный набор параметров для загрузки файла. Параметры + запроса отсутствуют. + """ + client = await self.get_client() + async with client: + url = "/uploads" + response = await client.post(url) + if response.is_success: + return ResponseGetuploadsPost200.model_validate_json( + response.text, + ) + return None + + async def get_direct_url(self, data: Getdirecturl): + """(полученный в ответе на запрос /uploads) загрузка файла + + Данный метод не требует авторизации. Получив все параметры, вам необходимо + сделать POST запрос в формате multipart/form-data на адрес, который был указан + в поле direct_url, отправив полученные параметры и сам файл. + """ + client = await self.get_client() + async with client: + url = "/direct_url" + response = await client.post(url, json=data.model_dump()) + return + + async def get_employees( + self, per: int = None, page: int = None, query: str = None, + ) -> ResponseGetemployeesGet200: + """получение актуального списка всех сотрудников компании + + Метод для получения актуального списка сотрудников вашей компании. Тело запроса + отсутствует, параметры передаются в URL (например, + /users?per=50&page=2&query=example.com) + """ + client = await self.get_client() + async with client: + url = "/users" + query_params = await self.filter_query_params( + per=per, page=page, query=query, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetemployeesGet200.model_validate_json( + response.text, + ) + return None + + async def get_employee(self, id: int) -> ResponseGetemployeeGet200: + """получение информации о сотруднике + + Метод для получения информации о сотруднике. Для получения сотрудника вам + необходимо знать его id и указать его в URL запроса. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/users/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGetemployeeGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetemployeeGet400.model_validate_json( + response.text, + ) + return None + + async def get_status(self) -> ResponseGetstatusGet200: + """получение информации о своем статусе + + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. + """ + client = await self.get_client() + async with client: + url = "/profile/status" + response = await client.get(url) + if response.is_success: + return ResponseGetstatusGet200.model_validate_json( + response.text, + ) + return None + + async def put_status(self, data: Putstatus) -> ResponsePutstatusPut201: + """новый статус + + Метод для установки себе нового статуса. + """ + client = await self.get_client() + async with client: + url = "/profile/status" + response = await client.put(url, json=data.model_dump()) + if response.is_success: + return ResponsePutstatusPut201.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponsePutstatusPut400.model_validate_json( + response.text, + ) + return None + + async def del_status(self): + """удаление своего статуса + + Метод для удаления своего статуса. Параметры запроса отсутствуют. + """ + client = await self.get_client() + async with client: + url = "/profile/status" + response = await client.delete(url) + return + + async def get_tag(self, id: int) -> ResponseGettagGet200: + """получение информации о теге + + Метод для получения информации о теге. Названия тегов являются уникальными в + компании. Для получения тега вам необходимо знать его id и указать его в URL + запроса. Параметры запроса отсутствуют + """ + client = await self.get_client() + async with client: + url = await self.format_url("/group_tags/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGettagGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGettagGet400.model_validate_json(response.text) + return None + + async def get_tags( + self, per: int = None, page: int = None, + ) -> ResponseGettagsGet200: + """получение актуального списка тегов сотрудников + + Метод для получения актуального списка тегов сотрудников. Названия тегов + являются уникальными в компании. Тело запроса отсутствует, параметры передаются + в URL (например, /group_tags?per=10&page=2) + """ + client = await self.get_client() + async with client: + url = "/group_tags" + query_params = await self.filter_query_params(per=per, page=page) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGettagsGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGettagsGet400.model_validate_json(response.text) + return None + + async def get_tags_employees( + self, id: int, per: int = None, page: int = None, + ) -> ResponseGettagsemployeesGet200: + """получение актуального списка сотрудников тега + + Метод для получения актуального списка сотрудников тега. Идентификатор тега, + список сотрудников которого необходимо получить, и другие параметры передаются + в URL (например, /group_tags/877650/users?per=3&page=2) + """ + client = await self.get_client() + async with client: + url = await self.format_url("/group_tags/{id}/users", {"id": id}) + query_params = await self.filter_query_params(per=per, page=page) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGettagsemployeesGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGettagsemployeesGet400.model_validate_json( + response.text, + ) + return None + + async def get_chats( + self, + sort_field: str = "id", + sort: str = "desc", + per: int = None, + page: int = None, + availability: str = None, + last_message_at_after: str = None, + last_message_at_before: str = None, + ) -> ResponseGetchatsGet200: + """получение списка бесед и каналов + + Метод для получения списка бесед и каналов по заданным параметрам. Тело + запроса отсутствует, параметры передаются в URL (например, + /chats?per=2&sort[id]=desc) + """ + client = await self.get_client() + async with client: + url = "/chats" + query_params = await self.filter_query_params( + sort_field=sort_field, + sort=sort, + per=per, + page=page, + availability=availability, + last_message_at_after=last_message_at_after, + last_message_at_before=last_message_at_before, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetchatsGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetchatsGet422.model_validate_json( + response.text, + ) + return None + + async def create_chat(self, data: Createchat) -> ResponseCreatechatPost201: + """создание новой беседы или канала + + Метод для создания новой беседы или нового канала. При создании беседы или + канала вы автоматически становитесь участником. + """ + client = await self.get_client() + async with client: + url = "/chats" + response = await client.post(url, json=data.model_dump()) + if response.is_success: + return ResponseCreatechatPost201.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseCreatechatPost422.model_validate_json( + response.text, + ) + return None + + async def get_chat(self, id: int) -> ResponseGetchatGet200: + """получение информации о беседе или канале + + Получения информации о беседе или канале. Для получения беседы или канала вам + необходимо знать её id и указать его в URL запроса. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/chats/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGetchatGet200.model_validate_json(response.text) + if response.is_client_error: + return ResponseGetchatGet400.model_validate_json(response.text) + return None + + async def post_members_to_chats(self, data: Postmemberstochats, id: int): + """добавление пользователей в состав участников + + Метод для добавления пользователей в состав участников беседы или канала. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/chats/{id}/members", {"id": id}) + response = await client.post(url, json=data.model_dump()) + if response.is_client_error: + return ResponsePostmemberstochatsPost422.model_validate_json( + response.text, + ) + return None + + async def post_tags_to_chats(self, data: Posttagstochats, id: int): + """добавление тегов в состав участников беседы или канала + + Метод для добавления тегов в состав участников беседы или канала. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/chats/{id}/group_tags", {"id": id}) + response = await client.post(url, json=data.model_dump()) + if response.is_client_error: + return ResponsePosttagstochatsPost422.model_validate_json( + response.text, + ) + return None + + async def leave_chat(self, id: int): + """выход из беседы или канала + + Метод для самостоятельного выхода из беседы или канала. Параметры запроса + отсутствуют/ + """ + client = await self.get_client() + async with client: + url = await self.format_url("/chats/{id}/leave", {"id": id}) + response = await client.delete(url) + if response.is_client_error: + return ResponseLeavechatDelete400.model_validate_json( + response.text, + ) + return None + + async def create_thread(self, id: int) -> ResponseCreatethreadPost200: + """создание нового треда + + Метод для создания нового треда к сообщению. Если у сообщения уже был создан + тред, то в ответе вернётся информация об уже созданном ранее треде. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/messages/{id}/thread", {"id": id}) + response = await client.post(url) + if response.is_success: + return ResponseCreatethreadPost200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseCreatethreadPost400.model_validate_json( + response.text, + ) + return None + + async def get_list_message( + self, chat_id: int = None, per: int = None, page: int = None, + ) -> ResponseGetlistmessageGet200: + """получение списка сообщений чата + + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в + порядке убывания даты отправки (то есть, сначала будут идти последние сообщения + чата). Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, + /messages?chat_id=198&per=3) + """ + client = await self.get_client() + async with client: + url = "/messages" + query_params = await self.filter_query_params( + chat_id=chat_id, per=per, page=page, + ) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetlistmessageGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetlistmessageGet400.model_validate_json( + response.text, + ) + return None + + async def create_message( + self, data: Createmessage, + ) -> ResponseCreatemessagePost201: + """создание нового сообщения + + Метод для отправки сообщения в беседу или канал, личного сообщения пользователю + или комментария в тред. При использовании entity_type: "discussion" (или + просто без указания entity_type) допускается отправка любого chat_id в поле + entity_id. То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его + идентификатору или личное сообщение по идентификатору пользователя. Для + отправки личного сообщения пользователю создавать чат не требуется. Достаточно + указать entity_type: "user" и идентификатор пользователя. Чат будет создан + автоматически, если между вами ещё не было переписки. Между двумя + пользователями может быть только один личный чат. + """ + client = await self.get_client() + async with client: + url = "/messages" + response = await client.post(url, json=data.model_dump()) + if response.is_success: + return ResponseCreatemessagePost201.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseCreatemessagePost400.model_validate_json( + response.text, + ) + return None + + async def get_message(self, id: int) -> ResponseGetmessageGet200: + """получение информации о сообщении + + Метод для получения информации о сообщении. Для получения сообщения вам + необходимо знать его id и указать его в URL запроса. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/messages/{id}", {"id": id}) + response = await client.get(url) + if response.is_success: + return ResponseGetmessageGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetmessageGet400.model_validate_json( + response.text, + ) + return None + + async def edit_message( + self, data: Editmessage, id: int, + ) -> ResponseEditmessagePut200: + """редактирование сообщения по указанному идентификатору + + Метод для редактирования сообщения или комментария. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/messages/{id}", {"id": id}) + response = await client.put(url, json=data.model_dump()) + if response.is_success: + return ResponseEditmessagePut200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseEditmessagePut400.model_validate_json( + response.text, + ) + return None + + async def get_message_reactions( + self, id: int, per: int = None, page: int = None, + ) -> ResponseGetmessagereactionsGet200: + """получение актуального списка реакций + + Метод для получения актуального списка реакций на сообщение. Идентификатор + сообщения, список реакций на которое необходимо получить, передается в URL + (например, /messages/7231942/reactions). Количество возвращаемых сущностей и + страница выборки указываются в теле запроса + """ + client = await self.get_client() + async with client: + url = await self.format_url("/messages/{id}/reactions", {"id": id}) + query_params = await self.filter_query_params(per=per, page=page) + response = await client.get(url, params=query_params) + if response.is_success: + return ResponseGetmessagereactionsGet200.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseGetmessagereactionsGet400.model_validate_json( + response.text, + ) + return None + + async def post_message_reactions( + self, data: Postmessagereactions, id: int, + ): + """добавление реакции + + Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый + пользователь может установить не более 20 уникальных реакций на сообщение. - + Сообщение может иметь не более 30 уникальных реакций. - Сообщение может иметь + не более 1000 реакций. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/messages/{id}/reactions", {"id": id}) + response = await client.post(url, json=data.model_dump()) + if response.is_client_error: + return ResponsePostmessagereactionsPost400.model_validate_json( + response.text, + ) + return None + + async def delete_message_reactions(self, id: int, code: str = None): + """удаление реакции + + Метод для удаления реакции на сообщение. Удалить можно только те реакции, + которые были поставлены авторизованным пользователем. + """ + client = await self.get_client() + async with client: + url = await self.format_url("/messages/{id}/reactions", {"id": id}) + query_params = await self.filter_query_params(code=code) + response = await client.delete(url, params=query_params) + if response.is_client_error: + return ResponseDeletemessagereactionsDelete400.model_validate_json( + response.text, + ) + return None + + async def create_task(self, data: Createtask) -> ResponseCreatetaskPost201: + """создание нового напоминания + + Метод для создания нового напоминания. При создании напоминания обязательным + условием является указания типа напоминания: звонок, встреча, простое + напоминание, событие или письмо. При этом не требуется дополнительное описание + - вы просто создадите напоминание с соответствующим текстом. Если вы укажите + описание напоминания - то именно оно и станет текстом напоминания. У + напоминания должны быть ответственные, если их не указывать - ответственным + назначаетесь вы. + """ + client = await self.get_client() + async with client: + url = "/tasks" + response = await client.post(url, json=data.model_dump()) + if response.is_success: + return ResponseCreatetaskPost201.model_validate_json( + response.text, + ) + if response.is_client_error: + return ResponseCreatetaskPost400.model_validate_json( + response.text, + ) + return None diff --git a/src/repository/README.md b/src/repository/README.md deleted file mode 100644 index 2a95115..0000000 --- a/src/repository/README.md +++ /dev/null @@ -1 +0,0 @@ -Тут хранятся сгенерированные пакеты генераторов \ No newline at end of file diff --git a/src/repository/pachca_generator1-0.2.2-py3-none-any.whl b/src/repository/pachca_generator1-0.2.2-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..ebcdcd062dd3b1b809dd97338fcb41c5503faeca GIT binary patch literal 128920 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

_ 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 Date: Tue, 11 Feb 2025 02:15:29 +0500 Subject: [PATCH 287/296] library ver1.2 --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fc6df6b..bff2e12 100644 --- a/README.md +++ b/README.md @@ -314,8 +314,13 @@ _src/generator2/_ ``` 5. **Установка бибилотеки с сериса TestPyPI:** - - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator1 - - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator2 + - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI + +5. **Запуск генератора и тестов:** + + - run_generate_and_test - запуск генератора и тестов + - run_generator - запуск генератора + - run_test - запуск тестов ## 📂 Структура генератора @@ -336,9 +341,12 @@ _src/builder/_ #### 🛠️ Makefile - файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. -#### 📦 setup_generator1.py, setup_generator2.py +#### 📦 setup.py - файл с описанием, каким именно образом будет упакован код для медотов генерации +#### 📦 MANIFEST.in +- файл с указанием, какие файлы следует включить в сборку пакета + --- ## 💡 Команда упаковки генераторов From 333b009a9d838bdd51207366988e233bc8bc488f Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Wed, 12 Feb 2025 22:01:20 +0500 Subject: [PATCH 288/296] library ver1.3 --- .env.example | 5 ++-- README.md | 24 +++++++++------- src/builder/Makefile | 7 ++--- src/builder/README.md | 27 ++++++++++++------ src/generator1/README.md | 6 ++-- src/generator1/generator.py | 14 +++++---- src/generator1/pydantic_script.py | 6 +++- src/generator1/script.py | 16 +++++++---- .../PachcaAPI-0.0.39-py3-none-any.whl | Bin 22867 -> 0 bytes 9 files changed, 65 insertions(+), 40 deletions(-) delete mode 100644 src/repository/PachcaAPI-0.0.39-py3-none-any.whl diff --git a/.env.example b/.env.example index 1cc2142..5e83e5e 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ +TOKEN= PACKAGE_VERSION=<ВЕРИЯ ПАКЕТА> -TWINE_USERNAME=<ИМЯ> -TWINE_API_TOKEN= \ No newline at end of file +TWINE_USERNAME=<ИМЯ для testPyPi> +TWINE_API_TOKEN= \ No newline at end of file diff --git a/README.md b/README.md index bff2e12..2ea21a1 100644 --- a/README.md +++ b/README.md @@ -293,10 +293,10 @@ _src/generator2/_ 2. **Создание зависимостей для работы сборки библиотеки:** ```bash - pip install requirements_builder.txt + pip install -r requirements_builder.txt ``` -3. **Создание зависимостей для библиотеки:** +3. **Создание зависимостей Pipfile и Pipfile.lock для библиотеки (в случае отсутствия или создания новых зависимостей):** ```bash pipenv install requirements.txt @@ -307,16 +307,18 @@ _src/generator2/_ - TWINE_USERNAME=<Имя пользвателя сервиса TestPyPI> - TWINE_API_TOKEN=<Токен пользвателя сервиса TestPyPI> -4. **Запуск создания и загрузки библиотеки на серис TestPyPI при помощи команды:** +5. **Запуск создания и загрузки библиотеки на сервис TestPyPI при помощи команды:** ```bash make upload ``` -5. **Установка бибилотеки с сериса TestPyPI:** +6. **Установка бибилотеки с сериса TestPyPI:** - - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI + ```bash + pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.1.1 + ``` -5. **Запуск генератора и тестов:** +7. **Запуск генератора и тестов:** - run_generate_and_test - запуск генератора и тестов - run_generator - запуск генератора @@ -327,16 +329,16 @@ _src/generator2/_ _src/builder/_ #### 📜 requirements_builder.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. +- файл со списком пакетов или библиотек, необходимых для работы упаковщика библиотеки. #### 📜 requirements.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. +- файл со списком пакетов или библиотек, необходимых для работы над библиотек. #### 📄 Pipfile - файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. #### 🔒 Pipfile.lock -- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. +- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. #### 🛠️ Makefile - файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. @@ -344,8 +346,8 @@ _src/builder/_ #### 📦 setup.py - файл с описанием, каким именно образом будет упакован код для медотов генерации -#### 📦 MANIFEST.in -- файл с указанием, какие файлы следует включить в сборку пакета +#### 🔗 MANIFEST.in +- файл с указанием, какие файлы следует включить в сборку пакета --- diff --git a/src/builder/Makefile b/src/builder/Makefile index 3b74882..c813423 100644 --- a/src/builder/Makefile +++ b/src/builder/Makefile @@ -7,12 +7,9 @@ endif help: @echo "Команды:" @echo " help - Список всех команд" - @echo " test - Запуск тестов" @echo " build - Создание библиотеки" - @echo " clean - Очистка ременных файлов" - @echo " upload - Загрузка библиотеки на PyPi" - -test: + @echo " clean - Очистка временных файлов" + @echo " upload - Загрузка библиотеки на testPyPi" build: clean diff --git a/src/builder/README.md b/src/builder/README.md index 392f432..0081398 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -14,7 +14,7 @@ pip install -r requirements_builder.txt ``` -3. **Создание зависимостей для библиотеки:** +3. **Создание зависимостей Pipfile и Pipfile.lock для библиотеки (в случае отсутствия или создания новых зависимостей):** ```bash pipenv install requirements.txt @@ -25,33 +25,44 @@ - TWINE_USERNAME=<Имя пользвателя сервиса TestPyPI> - TWINE_API_TOKEN=<Токен пользвателя сервиса TestPyPI> -4. **Запуск создания и загрузки библиотеки на серис TestPyPI при помощи команды:** +5. **Запуск создания и загрузки библиотеки на сервис TestPyPI при помощи команды:** ```bash make upload ``` -5. **Установка бибилотеки с сериса TestPyPI:** +6. **Установка бибилотеки с сериса TestPyPI:** - - pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator==0.1.1 + ```bash + pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.1.1 + ``` + +7. **Запуск генератора и тестов:** + + - run_generate_and_test - запуск генератора и тестов + - run_generator - запуск генератора + - run_test - запуск тестов ## 📂 Структура генератора _src/builder/_ #### 📜 requirements_builder.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. +- файл со списком пакетов или библиотек, необходимых для работы упаковщика библиотеки. #### 📜 requirements.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. +- файл со списком пакетов или библиотек, необходимых для работы над библиотек. #### 📄 Pipfile - файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. #### 🔒 Pipfile.lock -- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. +- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. #### 🛠️ Makefile - файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. #### 📦 setup.py -- файл с описанием, каким именно образом будет упакован код для медотов генерации \ No newline at end of file +- файл с описанием, каким именно образом будет упакован код для медотов генерации + +#### 🔗 MANIFEST.in +- файл с указанием, какие файлы следует включить в сборку пакета diff --git a/src/generator1/README.md b/src/generator1/README.md index 00e529f..d317b5c 100644 --- a/src/generator1/README.md +++ b/src/generator1/README.md @@ -5,7 +5,9 @@ pip install -r requirements.txt -2. Сгенерировать клиент командой +2. Изменить константу INSTALL_PATH в generator.py и ее импорты в pydantic_script.py и script.py в зависимости от запуска генеротора и тестов локально или для создания библиотеки (описание в комментариях) + +3. Сгенерировать клиент командой python generator.py generate @@ -16,6 +18,6 @@ https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml python generator.py generate --url *ссылка на YAML спецификацию* -3. Запустить скрипт-пример запроса +4. Запустить скрипт-пример запроса python generator.py test diff --git a/src/generator1/generator.py b/src/generator1/generator.py index 1072303..d2b96cd 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -6,8 +6,6 @@ import requests -INSTALL_PATH = os.path.join(site.getsitepackages()[1], "generator1") -# INSTALL_PATH = ".generator1" MIN_ARGS = 2 COMMAND_INDEX = 1 GENERATE_COMMAND = "generate" @@ -16,6 +14,12 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) OPENAPI_FILE_PATH = os.path.join(BASE_DIR, "openapi.yaml") +# Закомментировать строку ниже при запуске генератора локально +INSTALL_PATH = os.path.join(site.getsitepackages()[1], "generator1") + +# Закомментироать строку ниже при запуске генератора после установки +# INSTALL_PATH = BASE_DIR + def run_command(command): """Функция для выполнения команды в терминале.""" @@ -47,8 +51,8 @@ def generate_client(yaml_url): print("Генерация клиента...") openapi_python_client = ( f"openapi-python-client generate --path {OPENAPI_FILE_PATH} " - f"--custom-template-path={INSTALL_PATH}/templates --overwrite " - f"--output-path {INSTALL_PATH}" + f"--custom-template-path={INSTALL_PATH}\\templates --overwrite " + f"--output-path {INSTALL_PATH}\\PachcaAPI" ) run_command(openapi_python_client) @@ -62,7 +66,7 @@ def install_and_run_tests(): """Установка пакета и запуск тест-запросов.""" pachca_path = os.path.join(INSTALL_PATH, "pachca.py") print("Установка пакета и запуск тест-запросов...") - run_command(f"pip install {INSTALL_PATH}") + run_command(f"pip install {INSTALL_PATH}\PachcaAPI") run_command([sys.executable, pachca_path]) diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py index e9653bc..8cd08a5 100644 --- a/src/generator1/pydantic_script.py +++ b/src/generator1/pydantic_script.py @@ -1,7 +1,11 @@ import os +# Закомментировать строку ниже при запуске генератора локально from generator1.generator import INSTALL_PATH +# Закомментироать строку ниже при запуске генератора после установки +# from generator import INSTALL_PATH + def correcting_imports_in_model_files(file_path): with open(file_path, encoding="utf-8") as file: @@ -38,4 +42,4 @@ def changes_all_model_files(directory): correcting_imports_in_model_files(os.path.join(directory, filename)) -changes_all_model_files(os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\models")) +changes_all_model_files(os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\models")) diff --git a/src/generator1/script.py b/src/generator1/script.py index dc9d372..e7a0bba 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -6,8 +6,12 @@ import yaml from jinja2 import Environment, FileSystemLoader +# Закомментировать строку ниже при запуске генератора локально from generator1.generator import INSTALL_PATH +# Закомментироать строку ниже при запуске генератора после установки +# from generator import INSTALL_PATH + def extract_functions_and_imports_from_file(file_path) -> None: with open(file_path, encoding="utf-8") as file: @@ -60,7 +64,7 @@ def get_base_url_from_yaml(openapi_yaml): return data["servers"][0]["url"] -api_dir = os.path.join(INSTALL_PATH, r"pachca_api_open_api_3_0_client\api") +api_dir = os.path.join(INSTALL_PATH, r"PachcaAPI\pachca_api_open_api_3_0_client\api") openapi_yaml = "openapi.yaml" endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) @@ -70,7 +74,7 @@ def get_base_url_from_yaml(openapi_yaml): client_template = env.get_template("client.py.jinja") -client_path = os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client.py") +client_path = os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client.py") with open(client_path, mode="w", encoding="utf-8") as file: unique_imports = list(set(imports)) @@ -137,9 +141,9 @@ def get_base_url_from_yaml(openapi_yaml): file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints, base_url=base_url)) -cli_servis_path = os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client_serv.py") +cli_servis_path = os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client_serv.py") -logger_setup_path = os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\logger_setup.py") +logger_setup_path = os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\logger_setup.py") source_file_serv = os.path.join( os.path.dirname(__file__), @@ -161,7 +165,7 @@ def get_base_url_from_yaml(openapi_yaml): subprocess.run( [ "black", - os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client.py"), + os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client.py"), "--line-length", "79", ], @@ -170,7 +174,7 @@ def get_base_url_from_yaml(openapi_yaml): subprocess.run( [ "isort", - os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client.py"), + os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client.py"), ], ) except subprocess.CalledProcessError as e: diff --git a/src/repository/PachcaAPI-0.0.39-py3-none-any.whl b/src/repository/PachcaAPI-0.0.39-py3-none-any.whl deleted file mode 100644 index d68e9ccda28e7af98d11e66b6742be69aa298e7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22867 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 Date: Thu, 13 Feb 2025 23:27:37 +0500 Subject: [PATCH 289/296] library ver1.4 --- README.md | 2 +- src/builder/README.md | 2 +- src/generator1/README.md | 4 +-- src/generator1/__init__.py | 1 + src/generator1/api_generator.py | 4 +-- src/generator1/generator.py | 19 +++++---------- src/generator1/pydantic_script.py | 8 ++---- src/generator1/script.py | 23 +++++++----------- .../PachcaAPI-0.0.46-py3-none-any.whl | Bin 0 -> 23034 bytes 9 files changed, 23 insertions(+), 40 deletions(-) create mode 100644 src/repository/PachcaAPI-0.0.46-py3-none-any.whl diff --git a/README.md b/README.md index 2ea21a1..8b1127e 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,7 @@ _src/generator2/_ ```bash make upload ``` -6. **Установка бибилотеки с сериса TestPyPI:** +6. **Установка библиотеки с сериса TestPyPI:** ```bash pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.1.1 diff --git a/src/builder/README.md b/src/builder/README.md index 0081398..7dde17a 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -30,7 +30,7 @@ ```bash make upload ``` -6. **Установка бибилотеки с сериса TestPyPI:** +6. **Установка библиотеки с сериса TestPyPI:** ```bash pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.1.1 diff --git a/src/generator1/README.md b/src/generator1/README.md index d317b5c..488eb81 100644 --- a/src/generator1/README.md +++ b/src/generator1/README.md @@ -5,9 +5,7 @@ pip install -r requirements.txt -2. Изменить константу INSTALL_PATH в generator.py и ее импорты в pydantic_script.py и script.py в зависимости от запуска генеротора и тестов локально или для создания библиотеки (описание в комментариях) - -3. Сгенерировать клиент командой +2. Сгенерировать клиент командой python generator.py generate diff --git a/src/generator1/__init__.py b/src/generator1/__init__.py index e69de29..3775c22 100644 --- a/src/generator1/__init__.py +++ b/src/generator1/__init__.py @@ -0,0 +1 @@ +from generator1.generator import BASE_DIR # noqa diff --git a/src/generator1/api_generator.py b/src/generator1/api_generator.py index 4463cb4..23f0cdc 100644 --- a/src/generator1/api_generator.py +++ b/src/generator1/api_generator.py @@ -2,9 +2,9 @@ import subprocess import sys -from generator1.generator import INSTALL_PATH +from generator1.generator import BASE_DIR -generator_script_path = os.path.join(INSTALL_PATH, "generator.py") +generator_script_path = os.path.join(BASE_DIR, "generator.py") def generate(): diff --git a/src/generator1/generator.py b/src/generator1/generator.py index d2b96cd..54c9df0 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -1,6 +1,5 @@ import os import os.path -import site import subprocess import sys @@ -14,12 +13,6 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) OPENAPI_FILE_PATH = os.path.join(BASE_DIR, "openapi.yaml") -# Закомментировать строку ниже при запуске генератора локально -INSTALL_PATH = os.path.join(site.getsitepackages()[1], "generator1") - -# Закомментироать строку ниже при запуске генератора после установки -# INSTALL_PATH = BASE_DIR - def run_command(command): """Функция для выполнения команды в терминале.""" @@ -51,22 +44,22 @@ def generate_client(yaml_url): print("Генерация клиента...") openapi_python_client = ( f"openapi-python-client generate --path {OPENAPI_FILE_PATH} " - f"--custom-template-path={INSTALL_PATH}\\templates --overwrite " - f"--output-path {INSTALL_PATH}\\PachcaAPI" + f"--custom-template-path={BASE_DIR}\\templates --overwrite " + f"--output-path {BASE_DIR}\\PachcaAPI" ) run_command(openapi_python_client) - pydantic_script_path = os.path.join(INSTALL_PATH, "pydantic_script.py") - script_path = os.path.join(INSTALL_PATH, "script.py") + pydantic_script_path = os.path.join(BASE_DIR, "pydantic_script.py") + script_path = os.path.join(BASE_DIR, "script.py") run_command([sys.executable, pydantic_script_path]) run_command([sys.executable, script_path]) def install_and_run_tests(): """Установка пакета и запуск тест-запросов.""" - pachca_path = os.path.join(INSTALL_PATH, "pachca.py") + pachca_path = os.path.join(BASE_DIR, "pachca.py") print("Установка пакета и запуск тест-запросов...") - run_command(f"pip install {INSTALL_PATH}\PachcaAPI") + run_command(f"pip install {BASE_DIR}\\PachcaAPI") run_command([sys.executable, pachca_path]) diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py index 8cd08a5..85ea69c 100644 --- a/src/generator1/pydantic_script.py +++ b/src/generator1/pydantic_script.py @@ -1,10 +1,6 @@ import os -# Закомментировать строку ниже при запуске генератора локально -from generator1.generator import INSTALL_PATH - -# Закомментироать строку ниже при запуске генератора после установки -# from generator import INSTALL_PATH +from generator import BASE_DIR def correcting_imports_in_model_files(file_path): @@ -42,4 +38,4 @@ def changes_all_model_files(directory): correcting_imports_in_model_files(os.path.join(directory, filename)) -changes_all_model_files(os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\models")) +changes_all_model_files(os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\models")) diff --git a/src/generator1/script.py b/src/generator1/script.py index e7a0bba..80d0d1a 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -4,14 +4,9 @@ import subprocess import yaml +from generator import BASE_DIR from jinja2 import Environment, FileSystemLoader -# Закомментировать строку ниже при запуске генератора локально -from generator1.generator import INSTALL_PATH - -# Закомментироать строку ниже при запуске генератора после установки -# from generator import INSTALL_PATH - def extract_functions_and_imports_from_file(file_path) -> None: with open(file_path, encoding="utf-8") as file: @@ -59,22 +54,22 @@ def get_all_api_functions_and_imports(api_dir): def get_base_url_from_yaml(openapi_yaml): - with open(os.path.join(INSTALL_PATH, openapi_yaml), encoding="utf-8") as file: + with open(os.path.join(BASE_DIR, openapi_yaml), encoding="utf-8") as file: data = yaml.safe_load(file) return data["servers"][0]["url"] -api_dir = os.path.join(INSTALL_PATH, r"PachcaAPI\pachca_api_open_api_3_0_client\api") +api_dir = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\api") openapi_yaml = "openapi.yaml" endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) env = Environment( - loader=FileSystemLoader(os.path.join(INSTALL_PATH, "templates")), + loader=FileSystemLoader(os.path.join(BASE_DIR, "templates")), ) client_template = env.get_template("client.py.jinja") -client_path = os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client.py") +client_path = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client.py") with open(client_path, mode="w", encoding="utf-8") as file: unique_imports = list(set(imports)) @@ -141,9 +136,9 @@ def get_base_url_from_yaml(openapi_yaml): file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints, base_url=base_url)) -cli_servis_path = os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client_serv.py") +cli_servis_path = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client_serv.py") -logger_setup_path = os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\logger_setup.py") +logger_setup_path = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\logger_setup.py") source_file_serv = os.path.join( os.path.dirname(__file__), @@ -165,7 +160,7 @@ def get_base_url_from_yaml(openapi_yaml): subprocess.run( [ "black", - os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client.py"), + os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client.py"), "--line-length", "79", ], @@ -174,7 +169,7 @@ def get_base_url_from_yaml(openapi_yaml): subprocess.run( [ "isort", - os.path.join(INSTALL_PATH, "PachcaAPI\pachca_api_open_api_3_0_client\client.py"), + os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client.py"), ], ) except subprocess.CalledProcessError as e: diff --git a/src/repository/PachcaAPI-0.0.46-py3-none-any.whl b/src/repository/PachcaAPI-0.0.46-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..6f9ea96800cc8d6d786a0ca7aa244fca383bf65e GIT binary patch literal 23034 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%0Dwcd|i$UdiU_rsB&heAwOPRW!Cutz$t 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 GpZ*7gbmZCq literal 0 HcmV?d00001 From 19fd015dd1e803fc133c24fef0291b10fd1be2f5 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Sat, 22 Feb 2025 12:22:08 +0500 Subject: [PATCH 290/296] library ver1.5 --- README.md | 2 +- src/builder/setup.py | 11 ++-- src/generator1/__init__.py | 8 ++- src/generator1/api_generator.py | 4 +- src/generator1/config_pachca_api.py | 2 + src/generator1/generator.py | 28 ++++++---- src/generator1/pachca.py | 24 ++++----- src/generator1/pydantic_script.py | 10 ++-- src/generator1/script.py | 51 +++++++++++------- .../templates/package_init.py.jinja | 4 +- .../PachcaAPI-0.0.46-py3-none-any.whl | Bin 23034 -> 0 bytes .../PachcaAPI-0.0.72-py3-none-any.whl | Bin 0 -> 23415 bytes 12 files changed, 87 insertions(+), 57 deletions(-) create mode 100644 src/generator1/config_pachca_api.py delete mode 100644 src/repository/PachcaAPI-0.0.46-py3-none-any.whl create mode 100644 src/repository/PachcaAPI-0.0.72-py3-none-any.whl diff --git a/README.md b/README.md index 8b1127e..eb2b126 100644 --- a/README.md +++ b/README.md @@ -315,7 +315,7 @@ _src/generator2/_ 6. **Установка библиотеки с сериса TestPyPI:** ```bash - pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.1.1 + pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.0.72 ``` 7. **Запуск генератора и тестов:** diff --git a/src/builder/setup.py b/src/builder/setup.py index 7d34875..7daa663 100644 --- a/src/builder/setup.py +++ b/src/builder/setup.py @@ -6,6 +6,7 @@ from setuptools import find_packages, setup PACKAGE_VERSION = 'Версия из YAML' +GENERATOR_NAME = 'generator1' load_dotenv() @@ -31,17 +32,17 @@ def read_pipenv_dependencies(fname): version=os.getenv('PACKAGE_VERSION', PACKAGE_VERSION), package_dir={'': '..'}, packages=find_packages('..', include=[ - 'generator1*']), + f'{GENERATOR_NAME}*']), include_package_data=True, - description='A pachca_api package generator1.', + description=f'A pachca_api package {GENERATOR_NAME}.', install_requires=[ *read_pipenv_dependencies('Pipfile.lock'), ], entry_points={ 'console_scripts': [ - 'run_generate_and_test=generator1.api_generator:gen_and_test', - 'run_generator=generator1.api_generator:ganerate', - 'run_test=generator1.api_generator:test', + f'run_generate_and_test={GENERATOR_NAME}.api_generator:gen_and_test', # noqa + f'run_generator={GENERATOR_NAME}.api_generator:generate', + f'run_test={GENERATOR_NAME}.api_generator:test', ], }, ) diff --git a/src/generator1/__init__.py b/src/generator1/__init__.py index 3775c22..be8848f 100644 --- a/src/generator1/__init__.py +++ b/src/generator1/__init__.py @@ -1 +1,7 @@ -from generator1.generator import BASE_DIR # noqa +from .generator import BASE_DIR, PACKAGE_NAME, PROJECT_NAME + +__all__ = ( + "BASE_DIR", + "PACKAGE_NAME", + "PROJECT_NAME", +) diff --git a/src/generator1/api_generator.py b/src/generator1/api_generator.py index 23f0cdc..958d771 100644 --- a/src/generator1/api_generator.py +++ b/src/generator1/api_generator.py @@ -9,7 +9,7 @@ def generate(): command = [sys.executable, generator_script_path, "generate"] - result = subprocess.run(command, check=True, shell=True, text=True) + result = subprocess.run(command, check=True, shell=False, text=True) if result.returncode == 0: print("Команда выполнена успешно.") @@ -19,7 +19,7 @@ def generate(): def test(): command = [sys.executable, generator_script_path, "test"] - result = subprocess.run(command, check=True, shell=True, text=True) + result = subprocess.run(command, check=True, shell=False, text=True) if result.returncode == 0: print("Команда выполнена успешно.") diff --git a/src/generator1/config_pachca_api.py b/src/generator1/config_pachca_api.py new file mode 100644 index 0000000..6cb0487 --- /dev/null +++ b/src/generator1/config_pachca_api.py @@ -0,0 +1,2 @@ +project_name_override: PachcaAPIClient +package_name_override: pachca_api \ No newline at end of file diff --git a/src/generator1/generator.py b/src/generator1/generator.py index 54c9df0..77d3aea 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -5,11 +5,13 @@ import requests +PROJECT_NAME = 'PachcaAPIClient' +PACKAGE_NAME = 'pachca_api' MIN_ARGS = 2 COMMAND_INDEX = 1 GENERATE_COMMAND = "generate" INSTALL_TEST_COMMAND = "test" -DEFAULT_YAML_URL = "https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml" +DEFAULT_YAML_URL = "https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml" # noqa BASE_DIR = os.path.dirname(os.path.abspath(__file__)) OPENAPI_FILE_PATH = os.path.join(BASE_DIR, "openapi.yaml") @@ -20,7 +22,8 @@ def run_command(command): subprocess.run(command, check=True, shell=True, text=True) print(f"Команда выполнена: {command}") except subprocess.CalledProcessError as e: - print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") + print(f"Ошибка при выполнении команды: {command}\nКод ошибки: " + f"{e.returncode}\nВывод:\n{e.stderr}") def download_yaml(url): @@ -29,7 +32,7 @@ def download_yaml(url): try: response = requests.get(url, timeout=10) response.raise_for_status() - os.makedirs(os.path.dirname(OPENAPI_FILE_PATH), exist_ok=True) + os.makedirs(BASE_DIR, exist_ok=True) with open(OPENAPI_FILE_PATH, "wb") as file: file.write(response.content) print(f"Файл сохранён тут: {OPENAPI_FILE_PATH}") @@ -44,28 +47,30 @@ def generate_client(yaml_url): print("Генерация клиента...") openapi_python_client = ( f"openapi-python-client generate --path {OPENAPI_FILE_PATH} " - f"--custom-template-path={BASE_DIR}\\templates --overwrite " - f"--output-path {BASE_DIR}\\PachcaAPI" + f"--custom-template-path={os.path.join(BASE_DIR, 'templates')} " + f"--overwrite --output-path {os.path.join(BASE_DIR, PROJECT_NAME)} " + f"--config {os.path.join(BASE_DIR, 'config_pachca_api.py')}" ) run_command(openapi_python_client) pydantic_script_path = os.path.join(BASE_DIR, "pydantic_script.py") script_path = os.path.join(BASE_DIR, "script.py") - run_command([sys.executable, pydantic_script_path]) - run_command([sys.executable, script_path]) + run_command(f"{sys.executable} {pydantic_script_path}") + run_command(f"{sys.executable} {script_path}") def install_and_run_tests(): """Установка пакета и запуск тест-запросов.""" pachca_path = os.path.join(BASE_DIR, "pachca.py") print("Установка пакета и запуск тест-запросов...") - run_command(f"pip install {BASE_DIR}\\PachcaAPI") - run_command([sys.executable, pachca_path]) + run_command(f"pip install {os.path.join(BASE_DIR, PROJECT_NAME)}") + run_command(f"{sys.executable} {pachca_path}") if __name__ == "__main__": if len(sys.argv) < MIN_ARGS: - print("Пример команды: python generator.py [generate|test] [--url <ссылка на .yaml>]") + print("Пример команды: python generator.py [generate|test] " + "[--url <ссылка на .yaml>]") sys.exit(COMMAND_INDEX) command = sys.argv[COMMAND_INDEX] @@ -84,5 +89,6 @@ def install_and_run_tests(): if command in commands: commands[command]() else: - print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") + print("Некорректный аргумент. Введите 'generate' для генерации " + "клиента или 'test' для запуска тестов.") sys.exit(COMMAND_INDEX) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index a497cad..01cd837 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -3,22 +3,20 @@ import os from dotenv import load_dotenv -from pachca_api_open_api_3_0_client.client import Pachca -from pachca_api_open_api_3_0_client.logger_setup import setup_logging -from pachca_api_open_api_3_0_client.models import (CreateTaskBodyTask, - EditMessageBody, - EditMessages, GroupTag, - MembersChat, - QueryStatusStatus) -from pachca_api_open_api_3_0_client.models.base_chat import BaseChat -from pachca_api_open_api_3_0_client.models.code_reaction import CodeReaction -from pachca_api_open_api_3_0_client.models.create_chat_body import \ +from pachca_api.client import Pachca +from pachca_api.logger_setup import setup_logging +from pachca_api.models import (CreateTaskBodyTask, EditMessageBody, + EditMessages, GroupTag, MembersChat, + QueryStatusStatus) +from pachca_api.models.base_chat import BaseChat +from pachca_api.models.code_reaction import CodeReaction +from pachca_api.models.create_chat_body import \ CreateChatBody -from pachca_api_open_api_3_0_client.models.create_message_body import \ +from pachca_api.models.create_message_body import \ CreateMessageBody -from pachca_api_open_api_3_0_client.models.create_messages import \ +from pachca_api.models.create_messages import \ CreateMessages -from pachca_api_open_api_3_0_client.models.create_task_body import \ +from pachca_api.models.create_task_body import \ CreateTaskBody load_dotenv() diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py index 85ea69c..d8d25f9 100644 --- a/src/generator1/pydantic_script.py +++ b/src/generator1/pydantic_script.py @@ -1,6 +1,6 @@ import os -from generator import BASE_DIR +from generator import BASE_DIR, PACKAGE_NAME, PROJECT_NAME def correcting_imports_in_model_files(file_path): @@ -35,7 +35,11 @@ def correcting_imports_in_model_files(file_path): def changes_all_model_files(directory): for filename in os.listdir(directory): if filename.endswith(".py"): - correcting_imports_in_model_files(os.path.join(directory, filename)) + correcting_imports_in_model_files( + os.path.join(directory, filename) + ) -changes_all_model_files(os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\models")) +changes_all_model_files(os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'models' +)) diff --git a/src/generator1/script.py b/src/generator1/script.py index 80d0d1a..80b4b80 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -4,7 +4,7 @@ import subprocess import yaml -from generator import BASE_DIR +from generator import BASE_DIR, PACKAGE_NAME, PROJECT_NAME from jinja2 import Environment, FileSystemLoader @@ -59,7 +59,9 @@ def get_base_url_from_yaml(openapi_yaml): return data["servers"][0]["url"] -api_dir = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\api") +api_dir = (os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'api' +)) openapi_yaml = "openapi.yaml" endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) @@ -69,7 +71,9 @@ def get_base_url_from_yaml(openapi_yaml): client_template = env.get_template("client.py.jinja") -client_path = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client.py") +client_path = (os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client.py' +)) with open(client_path, mode="w", encoding="utf-8") as file: unique_imports = list(set(imports)) @@ -102,14 +106,17 @@ def get_base_url_from_yaml(openapi_yaml): ) other_imports = sorted( list( - set(unique_imports) - set(typing_imports) - set(types_imports) - set(models_imports), + set(unique_imports) - set(typing_imports) + - set(types_imports) - set(models_imports), ), ) if models_imports: models_imports_str = ( "from .models import (\n " + ",\n ".join( - [model.split("from .models import ")[-1] for model in models_imports], + [model.split( + "from .models import " + )[-1] for model in models_imports], ) + "\n)" ) @@ -118,7 +125,9 @@ def get_base_url_from_yaml(openapi_yaml): typing_imports_str = ( "from typing import (\n " + ",\n ".join( - [model.split("from typing import ")[-1] for model in typing_imports], + [model.split( + "from typing import " + )[-1] for model in typing_imports], ) + "\n)" ) @@ -127,7 +136,9 @@ def get_base_url_from_yaml(openapi_yaml): types_imports_str = ( "from .types import (\n " + ",\n ".join( - [model.split("from .types import ")[-1] for model in types_imports], + [model.split( + "from .types import " + )[-1] for model in types_imports], ) + "\n)" ) @@ -136,23 +147,21 @@ def get_base_url_from_yaml(openapi_yaml): file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints, base_url=base_url)) -cli_servis_path = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client_serv.py") +cli_servis_path = os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client_serv.py' +) -logger_setup_path = os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\logger_setup.py") +logger_setup_path = os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'logger_setup.py' +) source_file_serv = os.path.join( - os.path.dirname(__file__), - "..", - "generator1", - "client_servis.py", + BASE_DIR, "client_servis.py" ) shutil.copy(source_file_serv, cli_servis_path) source_file_log = os.path.join( - os.path.dirname(__file__), - "..", - "generator1", - "logger_setup.py", + BASE_DIR, "logger_setup.py" ) shutil.copy(source_file_log, logger_setup_path) @@ -160,7 +169,9 @@ def get_base_url_from_yaml(openapi_yaml): subprocess.run( [ "black", - os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client.py"), + (os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client.py' + )), "--line-length", "79", ], @@ -169,7 +180,9 @@ def get_base_url_from_yaml(openapi_yaml): subprocess.run( [ "isort", - os.path.join(BASE_DIR, r"PachcaAPI\pachca_api_open_api_3_0_client\client.py"), + (os.path.join( + BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client.py' + )), ], ) except subprocess.CalledProcessError as e: diff --git a/src/generator1/templates/package_init.py.jinja b/src/generator1/templates/package_init.py.jinja index db2297b..8139c11 100644 --- a/src/generator1/templates/package_init.py.jinja +++ b/src/generator1/templates/package_init.py.jinja @@ -1,6 +1,6 @@ {% from "helpers.jinja" import safe_docstring %} {{ safe_docstring(package_description) }} -from .client import AuthenticatedClient #noqa +from .client import AuthenticatedClient, Pachca -__all__ = "AuthenticatedClient" +__all__ = ("AuthenticatedClient", "Pachca") diff --git a/src/repository/PachcaAPI-0.0.46-py3-none-any.whl b/src/repository/PachcaAPI-0.0.46-py3-none-any.whl deleted file mode 100644 index 6f9ea96800cc8d6d786a0ca7aa244fca383bf65e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23034 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%0Dwcd|i$UdiU_rsB&heAwOPRW!Cutz$t z7qP9^uj58IXeieTrtz8gBLT2F88ToG7oi8{yeFEE?vs*Pq6%^#`GjL#WG}kLzSu9) zhS`=e_m|iOGSLN4eWi%J=_!`(FW|*u;SlA|jWC~Sv*t3CK9~hxL1)^b2I-9L*l3&TY0k;+oN|m;czRs1@GF02>v-;X z9Ng~eNr-VyK->6meXe0;Q}f=CkI$_r{G}*@BaexvlCBS%A4)jIgkbug-5(^TcBiE@ z;Gnc+G!H|+LRzcDBqgs$epfk+P_-2PDRb4w)k29dW=x+JZb<=ycTo`&*u3=u{M+dy zwsue!4~pM$eKj}d?PFm@6QR-$h5GN>?jK~IZNDOz>PMRi{-3m&iKC;Pj@(Z82mLk3fE?g6pb{^M(cPNOSUV+(f^xy3|>xoNWS`vcJBucdk!L5CXTD zf(8@<*3mqG$Bmbt+gaRqbVMF%KVm;M_G{1cH3Ua;^^M|K!oa)f~`kTk-02d?b6RS!w* z)#enZKiP6z31@%=p;Xwri{v;0%mMvaMNP(qNg{nMy6`cI+=1A2C@XpHESFsdQ(*>0 zv+<~ZqyaYCKgwTZgf^)aLwhJH!Ka*)3(*!iM%iD2Rx}1T{NYG)lHVPI4!Gf* zabuGEtEm5)*r`3IW{s-2XQn58Di$l-P?IkDMxOkM$o)6R{vUfyv2}y;=LdDWFaZFF z|0iK(V`pq){ZFiIR@eHGQ$K^vao++I6h!$kEpR`oSbm;OYQ<2CTmQ^29|AD(N7-@`n0{v> zYFzy7PX~u~0sJ(Q5rnn`2Y-<9`hsr+VU6+{&G0Lc@E(G4Q1kgt9Vdg{+DA)HRR>Cz z(Qn(yi)d{#1x%e8$2UJXs~nMile_bYTif%TEO8 zCH}f-mqYm=S;DQ-P+<|o4ixMFak}xP{@V-+VvZC^0g1OyFfObP6eVb5-2BgZ?tIqOqMDGL|kH?(8Jsi^gtJYqZZ5_X!-t z4im^1TJ9%E!l~2yo~heF)vqDN@!*usRa-aRc}sO8;k!q=v^26DNX=C;0KvP) z8Vbo)Qi2Vgx1d`N@!OEvud_Ly2x*4p^cxsCtot)q?v(N2c_rOC<=6KxYc^7u!deFm zQrXQdBlp{of0Ol3S^H4@<7w=L@-X8&`sG{WMu%|ZIO8u-9Py-+e8<(-%8u6#T$4Z&Vq2pm+IA%4gEQoEVr;Z@t##1r=M{^NO#? z=tDBqq20^-!v2UNwpSHfGL)^a4Y%|}lrpm<&8PwW8qU0b3>@5M@6n309PaBx@r&!#R1{yojJ)Md4ghw_p3TWrTk=Q&srAh0e3Fegv(IEMrdgr??sG+gv$gO zrw*9CSRW0SMjmb@`a+NuD9NxsA_o)wfR;Y)T%WPv5Q&o(UURthg=c*tpdcL|_r4;b zG9#PgqLOJIg@7AJ=?%UCx3U&A4t+r$2Ui=uJGx##T?-%LM0I_)`IpMf`45mNq!e=D z6wzc}pvg3wh;wSD~fx`2@_|+5_BI^V)WoSn1$#N9~w_p(0+*XzQX1zbel8t<~0D znP6>-)}(<8tkzsqL2cJ!#NWTrzf_k&8WPwto(`rXq#gT^DUr-dFsT2|Hi*I3!DfB) zzxj4^!f4Vuv5;4K!6EBffA0Egtl%I}&Ypt1@dnXS&+B0?)a?e}WOqyr741`UJq0YH z1t>FoB`c!0Ja7+q$~A!-BwhiqA|q^5%q?UJ!}7L*#c*CW9N6~qiVm_4uVzhC#k}XA zI?q?5cPJ*lGY(Vu!9C*V|Apg5mx-w~xP?CURj^{>iIf`Peg(-k3Q?73G#_?{V~mT~ zMY)6N=hE9kqKHg%&F067&fYs_*p>l2`sXM4{w1VY4OCw`1!X4<;U{$klFKX$$x zJ5hKLEuVpzGXoyy(zOVsniU8bOj;9v5#<|~*1VpxiiA{pyL8M8|H6Nd;;|kk37SU9 zf+O)nsFZYEPQ3IY&j<&iuQ;}b2y@!AYe1Wl=lxB)c-81{|Oa-X1A;i%uN2{ z>6J1R#6iU4wIMe9$dT{&(I2=G95n{!H{te2=ulAD+YCcA3XTNa0_p@#={Xxs3zZ9a zesX8{EUf%}Ch|QDx;j>OyO$Ye&^Ig9d{xFdo5C8zC|I2Ouzi)v4oBx=sJZ`(efY1#-#y>SI z01fijZ!?Ncz#k`KL?m`04M!x1QV};n7wd3`o5X~h%_}@FkR!|eX1ZhrG^%WM5aFQ7 zE?!TlvKuNs+VkxZ6V2}BH^HnW!D)B154o!VnLx35L=hmc^=aJ$P3}j6s3Ri)7c93C zZ55;Q=x_}7}F{G102RmIMQPfsXP4X#MjelqJ8t^;b_u9mx>9rdwFw$ zL$IvvJagn~C_(FRqR6LFdRX&SRHLol*JZB(XI90Bq>Kq8_7s^ZgS?w$3 zCF)S>Z9Rps%4S0Mvk#o4IbM18q#bbflSQzJ5qm9<=b+@ZU_FYlmKu5IA>w0y>g$u;rAT?jvZeK zXm(NoZpRn+;^Pz^DR*|y)ceIN|JCrDRRQTz5%_dCbLY#VEUQF?^u#+ z`uL`O4o4CVqGesNdLr(+-{|W4!j4n(x6e?#wY%uzcm}h@6`dWO9^$sfqv}IUMd{ZS zN~N;d57|;G)1>50R<7n+Hyl2@9@CtRS{azQ?bhsBoQ!sAsTI#_Z;^$>cNb?1&Sz7T zg~Vzb(IHp0Q{jyTBGVJDlf$u-&jrM2*(C=X`6shUqGB`Lf`5K%5k9ugxKGbnge*5F zqro6>wGL1cG-^NCvWbb+aP-=C_8_aDY!PH3yEdK$yPhspA!ve!yinJq`eKFn^jtl0 z*{67Fx_r#(*gwpsTJzfrRi3@Uc3yvF9-L$@=^zW%Ucb2x&UCA1q>uAM532roz&(i6 zYA>~|PA|Ox%fUa+`I@l#n#h^vRZVEwoU^RP&}-H5?~XeuQ?Pn}`dCa}jsTT9Wl>^Cj_i20ry}|KK)+6lf?D~p!`{5J=N4m?P9}B(Hwz2A4LaP+DNY#qwg6U?( zS-4rCT!tM~3xB1p*zHcf3xJXM=lYMjIj|jl(3r3KgKhO=$v(~N5c=JG3x>lk3*Re7 zx5Cb<#lvI3uI8yRCNiY=b4f9qn)%wZd&D#Zyljlwegqu@4}ha}&O50qu{O#eS-~HB z0mPo-Hf<&`BNyR#pZ-QqCS2#Pq1*l7^TN1-7wt zjBWlz__!JY=jJ2sg8hh}4C@xW!eI2FYffD3h9nnui3SP3Qo^r3TPd)VkLg93E6*KA zbeqJKZ0xXy>_EP@!YPP5R8obz)K$6k09>#X?FvH8Mu}F9IYVXuJ^~nCHUFC_oX-b^ zwl$c^++FsxHfbp$z{Q8wIT85ibb!f!|7y@#V%td(D_5$~ePjY8>-%!O**y|P&M}%r z97`^eY}P|s3H-|6F7(y`J*QEF;;`Q~!<$L#uQJ z^WPziE{bt?UKuT-ix3 zA*CwMSeLD2tb5M}r7T=v{{+{HD?UPOnM^T~3Gg7WIq5y1f=SC9WALQPP*nh~M?fUh zAby?j7{4{)41!C(N?6JZF%Y%m_zsK6_2fR;x#bmy44E%+&~sCo_SAZ3*rZ)MA!9Em zZqbFBGWS0OkNtYSp6~nx+s5nhV~lh8@rsQW&ZzqFcj_sq+-+j9B2E4B0}+{SM6x#L(67$-xswLRXLTL5qm^k($kq@>uqB+%-lMR7sL zLl)v%x1XnBP22B7vsmv+CKr`KN7iS^$kMe$g{u?V8O{S*G%#!ZHgs;QSfOumspzQZ zpK0#l$8{iBBdS27y?`2M&zo~5zHv-8r#|F&&XDFqyJ^D&A~^vTrWbK>g2RwxN<^<5 zLuFA_dDMg$SAa)=<+#Ew=vJu8ZIb5nV99BvU9plZiYKM#teU#W#J0xglmrlcieUDJ zRCHiDYI0G6Q? z{l2(^AGB$i8Jf<6#m`SjQ_hxvOtGl!5Co_ACpGX8knfIdHd#x+?PPLNPpItIC9Uu0fN^nt%(7F(f+kW25@j&mXHE~ApV-zFvbW^ zKJ*-928c&oy+)$Z{+z9$ArYliKl(JRH(7z4i^bV_!$djBoAVU=_1tPFN;?@Mp%}xi zsj2C=g`rT0lJY2`(PHtMniTT^NlY|hUo;^-)iN%VH>m$eACqoCu2QjBRDWMFb2%Xl z2aebpCu2YqcM=!=n4A3kN(D4We7c$x{Y9a%64>KlhM90EVj`1jpg31!@fpg62qn9J zl!I<((MlNWCSA5NiU_?3z&Fnwa_q7&8-=JL*rmkM8NBabsT&`@L;{~@^R*Y!#@}LM z6aISHl8=rRG-o71ZC#f6r}9CMdrhpgpd7>BNp(49M+u|E6{uBvj_pGj_h9}CS?SDS zxCy7OiA6@)6s|B*f<0jk``SaXS1Lj=hcCvUB;l|eT^OphoM&9mVcDgcLYsjIuP9!` z@R0|UfP|L0NGN1Z5d0;uBwJehtr6)s_(b$r;9FCKP$Nv#h!b+Ats6}3bJ2RnggQV} zh7laYL@Vfg+_mEc1G8kEc(jr_k&)`+nFTh?o(?HWLz}#oMuza9nRTISqv5LuC<1>9 zSSH{8_6nb})Jb20Og(`W%W5+ao5f!ICRb9QTglSV1w%Kob7u-$-~bjILem;?+kq|G z%MnT%p9`20)Z@w+IZ<53H}B}DwikEGADBY%CX|zN$#52j&EOZg$S*}TLf{$yGmNU8 zIl+qAekx`48f&Q6O_Fw9&9q<}Cd!DJtTmRD=sP$`C%RaBc; zb8SKWa4T@jmprgg>VUV&%VzDzu;BNR#Bqa2Oj1qj7?mku;Dj+}@5TdS$MQw^^xQrs z`;Jk3t4hJS3lR=fhKtoH7C(}cq{?2|h!jN;u_>*no7HA(^i8Xim~oD**uh(|k1mp% zr2<!Vo)RKjxlHdVot8 zj2AO>GI2y%`NZUj0$;As78}8O?0Tp^vStlw#;ndmPx7Q2Kh=1wB!VeI`|_c@>w?L$~mcCzWy2Efl)!CAP=h3A8)4ie-&~bz;LZ^7>_PWqL&DwTO^`H38MEBHHa1^ zqOKl9CnQ?*-hyTIvcj^2C>tSyNDvX-YRlDYto%3k&b?%>oBx^l=A50`^PBg~IeYe< z?|Yu-uHwdrZ&cSJn`VSv^xs;p*{bQc#H{U#J9tri(O3K8Y9)6w_)*t$4ie`j)iONW z#ID(w?62j6vzTG@c6faLT+?l8MIFpluTcx(@2iutj-3T_N9;z#%Cq%ly0%Dz6rGX| zMLdhBO7B*-Ce)0D1FFC@jom2C>A}u7rVwB$A?iAGtTjCRsp#qh`xh2!4b`1V^H|+S z;P7FxMx*02l}Q5g@#@<5%e#Kb))3$xFO@Kq11lCuT;0mlk)5-^jn1vVeWa z^cEr;R&v(5+5=>P7VU5J_$7YaHzz3s+owqDB(NF_R4Q>sz2WA;i}Lu|3$kT>M2-}m zt~;8wTk$Hko0ezn-tDUMNF-<3BAP2U72qvv$?(5xYNbwOG7o0bGX`524H2c%bY!^o zi%-QeCDu(8FYmbC&I@5&E&Bjq3-Mlg{K2{L#J`zIOdy~1qL)-KrBzUxTup02mv8ej z%nPYmZEglh^AHa17{!%?Yg`D=IBMb;wb%p3s0XJC_R$L2ay8yV<)jF;LLDN?)FNxg zhWb2Gm8Y5P6Bt#8qIqN~s6@xP)W?SJE&sZNa~2Ts&z>&FsvVTnY}E zzX$QqrgKlGN+TwIH_1!iPWy;ue%jCd@-0T}x>7LIX7+*1C6(@?2h{!3f>)tp+oCat z0R|?J-BjZ>Yu|jc>aTOf53K_~TYx^OI8U%koGIQ{QN(Q8L*@P+AW}%CmFHyXbg{ zE`rEUMInN{bMSesTlDVw56zQ0o|Vbjg1IytE+^<+>@ zb~W)wd!qEHsGYZto_=g;98-yh8v@_4I9CzufP=pt%Bs2+a9K3!Ee6@&pj&DoZ3fYy>wkSpAnL-k?cC} z2J4eVY`(sJ1(lKd-noa3JM-48He#E0!0dbb*T?tT^_ceJ`1(`VLwX5vtE3aPo?Ti7 zpe%c?z{MMtrG)%yTjn!s7XpC&-qs_bK)|Ns&2dF8K6zck$C>r1i=ixUhn7E*7fyg~ z7`sYF@_rG<*>+>rH|~6=D;AM(S#Z4ib%7hP)kh+sPy3v@bdKEBz+j>F;&&5)5;IEz`34H9sIcOGWzfPi(DPD!je*b=}`_2~nO9 zCCKG)tGhL*QXfkwY0qDfF|h=+bAVx{kNu~%-xF8qRdXzcly2tUmZ?!%@*-sSTbbUl zeH*`%bLi=bb(^(F*E{Qdx2VeEUVgAD>3%bN zmrMGcGl6-A4@WPV#nBVOG)>X^4^D;B0%6)K>3*R{WAjSyu>dOJJ_aQcpF||pGxzNgbg2fl1;mZ5J50%6yUekeI$<}Q6XXw$?SN!~$o{&(`aOT@| z2TLnh@Fz;(VoPvkHtE+6$UMu z)vrZR5cch-FY_5(uo9HVxGc;RW)m$cn?Rbz^K@H%eB{SvI!Guf0lYae*~#Gqxa4EX%oN^J~1l?zN$W!XCY z$i9yBz~@QB)8oMig^|s7Wg3=tPM#@{m`Q#krr1JB65233;~P&e6%TRV&5J?$LhEHZ z)=T4xV1{Nd>igc*(arhk`>RyQx2C*^s^S{WZsdbFYTVy%vWh*l$1>G zWVa&-%R?Dn$s#eT&6;dDva64TEpcJ`$EzTX z6#I)s%aENpxkk9mwf^eC8)DAu@Y07zd$pnME!bK#_trFC*hn?$#75|rd@d^Fm70>? zf5p|}{8CrVPzgjZl#$(MGx1fG#=1b6z;u3{q{dHv>7EAtWn6~rcv$Yu&tfEisfk{n-c)o7Kcf$F znYErIoZA|_gCO0XrE%x?rMy2;d>vLlPf_DfyMEKV1ixhfsw*Tef=6~xN2-GDWp85Z z>>hW2`j(t-GmKN7u~Yg>sB2KCG3zY2l=>B@m>s^Q~&fyj&ALp$g!HK4e~5 zZwb^aJeN;Pafdvu-@Nr8iP*3@<(qBl1pA6WO;&QI*cZj}ulE%9=NEkMA}AtvHWb=u z=pH({9)bjK&GdP3;;jr(9+PGibGN9gQ@tT+AfoIqf9!!6THV>-CiVEi8ZCNYM01FS{5b;~)HnAL$ z+tzO)0yUw+mv%&meMNk|lqaM!IwkA?Q+?gy(V22lxe902%qh{8&E-&!q338Xl%ogl z?<+$mg1P%z{HaRzxZ&yJ8Libnz}r8d8q2SBqnD2x@B+cZ^C9}~Ux9F{v1l`6B){tQ z8#*-x!BGfW`V|fuo41`!_he{H86kfhv$nt}SndUTkwLJXgwF`te-_oY*c3;KE`}IA zxPM=ir;DqF)5FK;C4F>7>i>k%&10WI{=5SoyTBwAI&Cf(?cHbjJyKUu{;sY<{pX(4 z0u?I!=>REW8$2OChma`Nl52%EGq^&6xJiU}0{kH5u*xLkv2t_B;mP}0X;$@2&@;A` z$aPt5VK^PG%UUR@I6M8Ga+5=)&a^oXL;34_W12*YCdynv9lfv+K_96>?JpbG$%*@wg2Q|GRQ4}8wpq6G^bnkJFhL4@PI&ATz zw{W=~%>(IZs^@TF+QAJ`DXws6yUj*xz#8-Y2%VUXEW><0^`pg@xyk?*{uFy7!l4wz ziz?lT&plptg<5sELngJ7b~9nofMOU0htl@9@-H3Sans241v6ftYfD0worcC5yFBr= zwoJzF>>3ddha#S96+6@lza^fAQa7lRWYsZ8*Z`X|V5GI~%0RfJ!;89EcBC;cD_%r}`5C;4tkgLdGGtdM&L=uHKxzEM?BH(tGK z!9doUq*Ji^OZsPLyl$I=ia23tLjPJynjvQwj-y4hSYbudxVS)XrZ}SseAinaIN2bA zf5-3#@Z%@{W||MwCy8@euxM{0Uwp;rjWU*f2QBX15Zmd!WMI2xul#2SM zmD#8WuPeM2^F-L6Fykuk3W7mB{ls?UDvxBDXB}I?u?(byc_aH%4g)eq?e+t{mnTAa za464VJVktcord<)+s1TFAmjY|m66d%k5z?BnKskx$Q*v*WV@J!lUFFvdLCQAo9=Fk z@g(WPM>kb)y-YAA;zP<`Dhe0Dxs`i}#}ZQ)MRC$Jv7BQZ{9FlW|ta zc$utGYC}N&qoQqVg{?lHZV9Dhx1;?|RNl%V<&VP=RKBuuPl|$t;l8RX!9&Vg=8u$d6Q z%Y9M3IbGD(l$NSWd*5E&F`_p$q(?e0aF%zkDKqfmB!BycNdH_l?jLu6!}$_GxzI4d zL4ygme(sR_G{!j0J3S={?II@6djpx))5zHz!gw-rZv||wD{`)N!yk))V*>`5V|^Bs za^Z0-WxV)-irGXe7~=%>sHGq>>+w1D+XF_`-2{0rxwn3c1H^9gewPj~e|5#+t5-=C+ul;>GdfyP@!u$*2T!+_L+Rs~#>G1j+*bq|v zUo;HA7bX$Ygmg+YNB=#Zxx&->{>zetiN+MapQ2^a(uMzn{#6Q(iN;h@o}$&!PO9_K zziKNniI|$fQzG=ne-M9F5Mlx`<)0@5IOWTU{k9AKTNHo^#B8KbfjXMM1^(GqpQWAG{GQT~ zzo%ig!kA#p2KE#jto7S6e`#mWQqSvQ|E9hQ`Sg40UmdNsIvzU8;%A~W&4pp~(Ph1# GpZ*7gbmZCq diff --git a/src/repository/PachcaAPI-0.0.72-py3-none-any.whl b/src/repository/PachcaAPI-0.0.72-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..3b259d80770e17b79a20fb03f779da2cd3dd6607 GIT binary patch literal 23415 zcma&N18`;Cwm%x19ou#~wr%d%wr$(Cla4#KZL4G3>geVC@2hjZdtcr6-mIFdYVWGG z*4%UK8b6FN6{JDIP=SDepn!ro)HJskr+(^we~SE`=-<=K#MZ>oz}e1`i9t`#!q&oB zPmkW-Lz-rMMs-$NeoC57igt`aX>^iql!02&-Vx3<#_bkvUJ=UP`N`GUE#}$j!3F#- z@V!erN4S?qmtME#nP?<+E}x6u3d0>77anK&giAb>P-9nd)tuMA@_XGH`l3SN6A zOIo~95ktOK*AehUsT+*n>2-tk3qa|+sJ_~n&>)+sMyuP|UdNc%lkw3YsRmUcNVy_u zshrX!1QTmX!a}~`0-Y{6z#*TWvP9dJYIYe{iVF4D&5J=Mo5uqK&%eE10%m2qifviS?p_sB<~WjM);6 zi7y{lK{5DHBcJ$VHw%12ba#FulM1FPEVFP!DTl_1E$)e>XKSu8mfyz|(VonS;SUHfk!%qiO+2%vcGJ4)XZ`hF@ zAhN2NYW0%mq-NTB`+i~deDzLCSFwE1&IXPWTDDksVKTPs>)%Oq&-hB8({++->OQ>dXy12816B*hRTA*Sx2!W>O0`IGOa!X&hitlEl~%vZN5 zM%}9V{0M_;B_t}w)=3MD=wdb~ktkIV^Go@^lPNY+-!HT&OhZKgeZ{Vo7_}vgHZ%B2dBKoGiT92S z$sp^PyX8W$tH{w{PruJjKr_=pepodYl>4ZfavzYotmR#8?2_?I#-T@#Pa&G4FHESqiWe|nPs^^7 zfX-#^1U9=&-2`e^pKC3yKkI|!N~BHt8!+$s8inwzO}g>iRMNklh4+b_rs=BXkv&#> zOC4JVSM|75B~O~bfhSFiydu;Un1rPt_s$~Kcxucwi&^9jVF+rSfiKf^s(Z3UFNf&? zW*Mp3XNR=Cp?H0`+g`9ZM~M1L!LB~pjI?E#`I|q$<3bamdC z7Oa#i-w@&073+%+cx4lLZ*0Me%S}7b=0i!+g_inK8SvR5W-|BkSW885Hkz*X1WDoV zw`cO9yO;Z_0L!MiMFCO1JB!W|Mq6$%J=ekg;d$Y(G|lqD%=t4ySYE&(@9VH@qO-#-oatWCv{VLgD9;WMC5T%O?-MuD(x7?Dr2EV274O8to=s%$3M^ax7# zTN}%>!KljAWQ)mB{vIM~3`38zxKGle*<7{P`UAf;^hY1tpeWMnN-=n1jEO{eRMFLR z?{lv!BRld$wMYF7=nohr#NnnOj7})SdUdoFRS0z5myrqRu1#A0UtKis9HEA#YW;cK z4A#j(aTD_QZOW$@#LRhb8#8HM%*SDupOcqZPcwO(h~ANt9;!sYK5rW{yikp(opgUq zW$X1$zHW47+(*~*JHfj=VxG7CFf-vHZQFTL7LAnA%OwsFyk;iMW^sXRlqZ{lrTh4b zc<;?vO-d2wnAORJZnwT0g!_;XjoCK6B1I@$)f5;>XIlqo6MiHZYgbtRv^iwNoE8g0 z(=RjT5X9v1)shy&b80MO3+i0=YVvGo9rPmj;3od`87_^&mF;33_eW6|)77Fq)O~Ae zQt&PVjpRJ~E%L`F%(FmB>D4MCsK%@ppwG@O>Uih#{Ua`?>Xru2Y83>zVV8=;fB2n& zCqo7jG}D%nU2dj)iGF{1&q9yF=a1vQ4w$A>ncG{#hWBTk1%CB&(3YT?!9Bj-K&?{O z-bdIpr*d^dwT~A>XHoqAu=m$0KiB2gW&}UyBA4fv4M~sq+=Q-5F5@Q!2tQ$f98|1v zpe?hU0OUZ!s9yvsge3ORv7avoEC0irK9AsOg~gu2YhEZjxhEl@}JzbC02x54L$6FN{T3atJ* z_qc7Fcjo#P#SG~snIun@Cf1t;BVha%v&G?zC(&V)?%XD_OLx=uk$JPn+T=qY?+gvx<(;8_#ZUx)-?9yy&F=*}+ zf4Mr#j9}NyVL<(`^BGwv+2kxvk*k5tQ>W3H7iM{2%*O-hs?T(vPg#QZi7zysh`y7y zhfnVl6g9kq|n8_h{+yNM@!4_{@w-ySwVR7fo zvCqpRVt<3iHp%4Su9GTIS}}wN*5b&qp@Q%gb{ULy++l=U%!+%z7alccQjWLE>98Z;>VASKeO! zh0HzI(xC;Z4O>(#dc(>0K+6+|-X^^P?^Ar|t?C9p+2fic`wOOvkr3L0T$p5%rTCtO&9@hxW0#ftQAzk zi}X$^PfA3hHAttLo`Yn*Ndut-z>H8n5Rp4DPCY^^)Fbhs6e;j7?Fr;@dqwmqkRmI4MPg z5ZZa|wbtdI;kg@;Th$YzQl0=UX_hZ0ta7Q5pmHuCZ^d#E@8CDPV~o_ApK(HmucQ2A zr4+q%rkwgN9!yRfyg;NE7;i>c!&J(4YGEa?liT1{?MSydBD&2MNaR0WWn81uF(=bP zE+VzZa-oUuW<65w?p+OrX2p^qo&>I9?W-PmBU%5{%|B8$yl*MBg?YE2TRyaC5c8v8SnB$>JIkhM^ z{HpAyY%%KBD9_(*AhcJtC*2*ed4?9_t7>7uAD+0t1!2snJ~*RBC?mpQ!!A?9s?#Y2~7=|Jv^blQAEc23G;zPTR&Y%uDU zl2*{>x_y_i0>|V8+LH`JJRjO&_X;3%*c@(?IQa)na2?+$ZMU*`GWsm*1!gHJ8fzH6 zSY&4bcS%Z5qIlAvA2+CC+R4E5S=25#+nGdT3h9Iam?0Mh}{?T^G5A!JLgt<`TQEZm^ zC!8uF4$N#qM@5;PW^`ZGx4-^`7wF40_*!xy)fT=o>0&C4M`JQI2qmF+Y>*E5{Rea8 zePuM$+E<$ozmxv)x6J%jH~$p9)^=uQCXV0I#@WUG8*XeA`)mgY;kv}f`CpU-i^-2G zl-$zWUBYzTVioK$e+0mo_xP0tq)Pn6c>f-7o^4zNeHZt;Mr|FgwgJcvzQ|0rXfUY+ zWZ)YP$ff0D2LAZ2?*^`2na1_w7;u7=;{e}oKe)0bU8h|7=5tso_N;>~nY#zSEmPZ# zci{hQj;fEUCRw$0Z6zcSkUtR+(7$|wf5RaY!+#<1_qH@?O4@CRp?2fk_+gSlD%IGu zf_p-b|uPT_<;7Y zL$?f#A|0^k7oRnxO>{>BoHcIv~IP-YocjegmN9P_3lIzgbFeH)~f zTY|!7!L2m-bcqk%>%!paNn?Gr^USPa_xBbLTU0k{Z|80gB;&n|No3;STzB<)xoerZ zO_)2Y5o2@fY40@3d!?)^CuTM3E#ajqB|vZUf%uF~UzKc_4zpKBiWB?hFt9x4o0bi^ z;6MSs5Rax8XoMgaUTfo2)Ksjq`FEk`Bz+q7zPVp!2wlAuohvexvLdid*;ck##V(hQ%GX z&g07v0G|Tki(5;qLjDPXUo*H%t*ZKiO2a4oj4pRx{AmfP8^)!Ls8>_nrUzgZy9^%`Ui;X8 zZ{*`6JH}b8eOWf98tbX&hGh9rKQ0T4NhpB9C()uB9Dx!8B z;uwPv2M6^o>kFy2+;hH z{6z99RH+=F|9WCC)9sXp;n92owDaES_*zfF1W9Zry+btstIf&GwgzlE>KVIOJPn+H zb1WRZXQp?H6TTCpa%iK@*@^!2EE`RSC#vVq1Wi~pt*vWz?zr8D1R8w`V%hLSkYk0q z6|o8$@xBAql?M||X9HEIr+xxG81ysi&gS7D3W5T*ASG(NJs&Swimt-C1!b#OtsEQv zmY$!$)qa^&YT_CcM8*#`c<^DdpJIWQLNQEJCZsWnS%W>$Y!j#}JZcAxg~&R?!vbJ; z{V(DY?G=@Uu@HsRdlqekfavN?c#ky-m}@BE7PasVz%TCQ9>34q7S^nQBQX{+64p&{1>Y+pQ zM3@B_g%*i)LmD!wYrrfs-7@i0OLqVul4mTnVnYC84f9t1Tg5Mq?MJJAp2wh4Bi2sW z4QlGq)oY-uKy`2m`=>-5g$KdkwF_)-iy`!)Iw4i1{DC(iIb$b>b=J5pzfX>B++k9R zX`nFD){2BWZHwbYBiM#H<(EhBmrh&<-)nov8W7m({uIS6WqyP|6?!kRx9w_NJ8$eF zl&G&gBonGeS#?b3@0_hx`@wLe~PV5Kjl5V?er;Wu3SB7=YiD>YWa3W%X? zVjJvL$H2T+>^8||TXX!2Cc>lMJFWyMw%=41;*H_H)qr&vd_q*l#lvhJ8MreL>9(Uv zqcO;_Dx!H>KwAu3E9;B;mYVD+f1OFD_aY8PM+m=m07PQki$jIXPgk46&G-CW;Q-&M z4m(Uiu52>0!-qTr`YwW$HOi$0vKoWNz-T?t-c$S=!($$gtas9kI_d$& zM#PV$w#5Z=?=KuzE(80p;SGa^_5rLv&7Gn#Ztd}P_(A~&vMF?WW>Pb#g)s*ve=Y9t zVZ0sIO=Bz*J%ystGSLOdm$*q>Rc_FWWV?&l<2 zHJK7^tdw>l<}cqAmkm*OmR4%@owIg`%h^zNu~-*rhGs5pJnF-oNo#E<{AI~JcRW0w z*;hPpl8iH!RE$MhBt+M0VqGf^>?FmN&6eKY=%`J1AGK0pFQSlz9d$K-l(Lul_`^bP zv-ivHCOgeAME$^_uCcK=t+y#~!C>k3gT6p8i7i5uk7PMfGs($Y%E?*yyi+fV-oSs-}pU-)aL05Rl=wv5WUVz}>^xz}DHq zNYBa0(Zb&O8|7nEr)(Dlkh;akxuYiw>QTML5*(q3l9d#H&BF?f{!Wx_*r}r1P&}!Y zjQ6CBhYcs$gBK#~XYs48dlQ?i!P|5BszV*=_<29|JQX|AcVSXCf2sq2+9WOI=OB)V<56~<~%p##Z5NFX|3#slt!MWs8<8^n+lqLl{J2n%e4 z0TIXbL$av5$E~hIR$zm=15FJ0QJP$(Qhz7+NQa3zx+cvT_aXd>q)B0!1Pk6u6lRS| zXpdwb&jb)PS4v)S#~>vH=S@TpR8-ryDiu4?>vvC<7w&`~RS=6($ap9c?UJu;28fNDTA`-0XBTBh`|I{8jkhwRlEY){oqo53 zo}hnzkiG?!tM4n8$dANuiBW9|@KGI;?iEYyAh6}~x4;hm2z_5v`-O3x$1?hdX$J%) z--3#Le$S#T@CiK5?s~KXN5QKs{;ztl4oOfztH7lNuaR*>??}ntp}V2JGs1i5dBC`B zMxcA#mfy>Js)fNr%oh%prNRR!c7m~zvE2A1Tz%|-oP;@dO=V0CdP>6-tQ>ohbS#X8 zp`3aQEJLF zFvk~kC&pb&8I^22BH2;cEkvUq6b7o z`kejy{v<2YVVs_FW;K(MQ;33vOrA|B@iB;23QB!EEGU>3$%Eblb;4e;4lo}b!DuK6 z7(*&Z#G&_JQ}*lsuDKAz_z58X6uUxzgvynsR;QeRwvrGFuj7!W)RMC&!q~sAL%bnu zvP)ki;UqFIw1>S5kCGDYl}vW;uANjC(Q5E_WUF0{b}${91vaFWhANbi?u?!{%bnlR z!afC26wHW6j*2K770-N;um*S=vTTyT5>UP4jEe<&vgCCX2Ls-hYpSU=j z`lx}DjSoF#W#)Czw^xv|1)SGmmNk@$Vbn!&(;1MA{1R1=fhK;99Yw1Rs)zN$lfu(Eyq{V5^jy_9~PgL)0plx(0pKV}}doF@aDC<;Zfv44}39 zY@nVh5vXglPHMWy_DrWCGLM^K_LKXO5x{pb*j20?@N2Z=ai}~LHU2uL1xle){NAaO z{8Xf?t`L?c9-x#Rpe*}n8dc_oK6GhBbI@~9IJXT^sHAT5NEM`l6K_X4rJWH`rPM66 zf)FhmW$}SUhf1tb_YWBxCft4~-D{=|nx%$+7yKm_(j=`0&Bjmj{ZDEq)!Ff#p(_tTPhXrCcZEf13ic%t?OHI|xH zOQuK1+%_e%4%eD43OFQfkXKUJ6iM2E<%{y=k;@fZ9*&e3-x2P7p=ugw2 z;wD3NcrMIL3zNzkW9D>2TBXlthV^DPC+$Bnt`REgpORlw^{w;}snfEB#xD9KoN}4} z5MGGQb^qqXc|&rAeE%ZQSKl^xY2Wh3_4YzK8%ld1t83_H_shW8Mpu0z@;7USM;jsaLWcE626@^=X zu7)?HztQBW^>nQcJ4mwFCx4#eZ8Ts0dP%H+pznP9TzK=i3@n@Y7!d3?k^$z*f{Zg+dS`K>-x!t{-9$`|h$JtNL;wse-&+o49 zzFkZDZQp`YUxf#P|72l?VkymUngR4pIsVTe{J#FfP;fS}v9~sGHgWoAvjONotonZy zqPIw?&~5(J5b*sF(*N!L|0+p;lNNeQ3tLMA8%0^^0Y=PjjK2iBFhTHAUG6_zk@_li zdBWmLbxbpp4>s*5@s5^?{6xSFxE|PzzebBMxhP;+4t=(cJ@|9Oe=S20m5nN@@WhJ1 zO6a5trTAD^M;G;htDeWyE;y43Com=JQKMqmg2@$f- zDC<4eoJQ242!9l&m`F#}CaV84`DXhw+g*l{-`02O;Q4})kv%u2!BgH2WWM%?_yjP^ zMRDPzxz}=&c~OE>qGoG}b^nPdZUDbzVk<_A zOYPOB&vou5MQbh6)p7@GD|^fB_VPA=2gUQQa@Hh`P&MJxG!T&xG^w$98?BOn&&*Oe z4ZfT|x1PTDc#HuFR!hHM`!Z22_wVm|U?CbsagkS)2(b2H6FQ7dgKZeb`U5o58LEW` zA&;jNz8Du`tqpB#ZAFSVSf#M2Jc1~sc(@&bzutes{jYFc?&WBwe}iuFcUgt*e+!q1 zt+BnG#di;Zje(J)-M@MW{wr=%fNi@CHY8tyy03sbWDy}eI-d==Rsp65gMryF77u2S zfF$#*2$^4`DTDSOJV>9Y3>1n~{kF#?pX*}Lep^0FlK zUvfo3E#26P(d+0R7fIjbLs}#A$4|`h+D7kCwy!qyD_M2OA05>s`Epal028gT4gz^4 z;KcrpdF17nns;*~Ot?#E5aiq;ut`^|u^c%~a=wH--A#4zH{6D;0i0Q7#`Ol+q+Pp` zWT|X`GHv1M!<}#u3%8OBVLLuQZlrBkMBMnYE%sqyO7VN@zIS8D*g%BLaIbN6qw*-^ zkKaWWIF}Tmjp_0*7$}v(V=T5FI3ablvFA&v?o|_mN4>F*JB)5yNlELOw!q`@nlsjx zG*~eYw-WG`8gB|2hDY%EbOz-&9 zh#og-15KM`B0Qj{nRw?^3QCX8T$~uNvMj4m7bMe?v#)P~*<~Kwv2F)Y(#G zc_6B>$mAi(VFNSQN*MOOz|ZV{tv;)Kgo~S-V35t&4Q!75_hk7TARoq4^etu{o1_~e zltl<}tQB&IGIvX$O3$_6n?`7aOyxWn-aK_+%zfj4tJIkt{bxh$>o}^-7F5*IICNkQ z#-ZX<+#J1aEpl;bQ){|&2SHbvfwI&^jKsV$TwQk;Z^0b3;li z3zDv_VMH0}5w8X+aUXTj#+Y6p{P;V2iF=3gWb6f=#8;9YUHrt)4aujd6Rq$Uwux<# z`7fzQpxkcR$AWG>zlF%n*&}3mCS}Uq-=OYLb`YkN(b*Q)9SRudtg5TAAM2XcpM*0? zB{PvneIw`R_Qx^zK#r<=I!!J~Q%tt?<{_Na`EXfa+feMG-DaSW2V=D4!F zoJk!(FVpcqE$2yg|H@V(EF0J5v_G8@th^*ep`PBp71WC5Xl*IfXqccVOHt!(LO&%o z4Awp1bpC+lCG(@JDq~TW*ROEY4GyS4(vQXq%pbGz!anmGx9fd*Zq7pXFuswzo5M72C7rCTI*&PX+c9u&sK7{_iQ? z814^A&v%N?`SJfN#oHOXSeyJi#h0jWTK@U29k9RPmBIj1>CjL;6w+Gf2PeDj zKpWCd)ufnDbMOGXplCLrMF+e=@u_OqjAdv#1$$XNSKr58V$3p^$p8iM)|*&X>-m$x5X zAG~y=H@*(bh?T#p0JJ-awDN6YvHO_4&_7rCe>784kpOwQKissYFoTHfrC(blpp2u4 z{W@N5&&=y<;Tg&{Mm*?FpdVk0Rw10SIk4(Me46y6bJ)rD|Iq=X4nW3iG>%>PWqfOh#XohbjEk8x4K>|6 z30`xPEvP?nry+N7cbusr-LSqbd=plw!3)VBQs?X*oZICeR|mlEs)0;aQLL0Q1G&c91bT2?NSOx%7!ixAlncMkM%d5>Q;>Y2a9X0! zkmVHtBU(gXLGC9YOi!HI4w1MV2#<3BqOq3-V{K2nCxW(UWy)qiE^v_rv15;}e9b1-YorUmXL-UkYe44eTGzB< zrr;z`)CVOO6&_TP6l?jNrkA>P%P>UmQnSEHPjep*x&3Vbtz(Z@5Azg*5OwR|L~$y6 zJWxtQHgl|nln@bbpm*fgzNjj_;oL@`5({i_VQW#nS_)7dQw|t*u_`+Mh$!7CMSOMh-GvhostwR!P@n-@J@hKU}U| z!9;yGv|m8_0*d!$C5*fMxk(M&z?(GC5=o};`{5!G)!g;z-QNn2h(2A$JF?wl04G%V zoHeN~DT$a)qem7~V~@oaC%?Q@(t4d=V-28i$-7)m_#WvjA38P9YWG?730kQLv53ci3(x4{h18{4tbHP+Lfk>5Jy z8n5tlyJ8bme)k6Q-10cM-`10o;2wjw^5OYj!ONxPzoHzSSy2W^Q-(wxkxV9E9W>pS za*7MV^*wpqOHS@gNoyd$Xv=CIgnfp#REbMTT@AZcISf-b7cG^$>f>plMjA6^Oo=q7 zLLj=RiVOU?@dp0e;UvDcU!DL?(0+9}JL}_XVMQCM+6II6Pe1uzWS?#CR|xgDHWU1R z(`F`)j&_d!;rKcUGnNC4aKqOj-9a}c(8)Xk1!0P=t2WLX7I?!=DMRt&eSQGx(++vt zL~@k?ePf?I-_&3vZgE8o7$oe&IUvt#Z-4jG_^+7Ae6&8~J{p{t?x!m-hHE%%@-+?_45gm@~aCj6* z{hMIvL=}}jf;{+dz*C;W0kmr zaOzN3@;z8CIt?bn4T@(H(3WI?Hrn1RZ0mM2cUgq~&?tpoKL@X9 z3~U4-kmjbmIRx)>BRJ#5ru0?O{57#te@e?9QT52mNd8bNQL&*RTkwlIUW&~7N7ur? z_L_3@8g=O#bvv+>R$i_rdjyIl({1DL22gEZ=0wB)}`q;xqPSx=kt9|+&GvXNfRAqhnTaDeZj1B zvrhhmjo{~?VZatfq+{qkxTh!<`bNvOL6W!H(R1xK!`?kR#&J)l&+|RVhX{&`x3hP$ zMaB@@kjz|h;$Il)I~;jvC{J0*TzrDdT*AzPCSBNy=#?z(IS^R1TK9HQ`KJ-_!zHb; z3{E)!4Euvz1u0ygGcgSw!PbX^Lz@6WI_WS{YobE{*jRnx7m|oZMU7^}rD#MqVFkGP zT!)U6K~L?2C8wGL70bw%?ZkPEwwa=)!SG1-J@I6Dyc%d#BXP?GM;OxTΝ6Q7pck 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 Date: Sat, 22 Feb 2025 14:37:50 +0500 Subject: [PATCH 291/296] library ver1.7 --- src/generator1/pachca.py | 12 ++++-------- src/generator1/pydantic_script.py | 6 +++++- src/generator1/script.py | 10 ++++++++-- .../PachcaAPI-0.0.72-py3-none-any.whl | Bin 23415 -> 0 bytes .../PachcaAPI-0.0.73-py3-none-any.whl | Bin 0 -> 23506 bytes 5 files changed, 17 insertions(+), 11 deletions(-) delete mode 100644 src/repository/PachcaAPI-0.0.72-py3-none-any.whl create mode 100644 src/repository/PachcaAPI-0.0.73-py3-none-any.whl diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 01cd837..2d28ac1 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -10,14 +10,10 @@ QueryStatusStatus) from pachca_api.models.base_chat import BaseChat from pachca_api.models.code_reaction import CodeReaction -from pachca_api.models.create_chat_body import \ - CreateChatBody -from pachca_api.models.create_message_body import \ - CreateMessageBody -from pachca_api.models.create_messages import \ - CreateMessages -from pachca_api.models.create_task_body import \ - CreateTaskBody +from pachca_api.models.create_chat_body import CreateChatBody +from pachca_api.models.create_message_body import CreateMessageBody +from pachca_api.models.create_messages import CreateMessages +from pachca_api.models.create_task_body import CreateTaskBody load_dotenv() pachca = Pachca(os.getenv('TOKEN')) diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py index d8d25f9..5a68401 100644 --- a/src/generator1/pydantic_script.py +++ b/src/generator1/pydantic_script.py @@ -1,6 +1,10 @@ import os +import sys +from pathlib import Path -from generator import BASE_DIR, PACKAGE_NAME, PROJECT_NAME +sys.path.append(str(Path(__file__).parent.parent)) + +from generator1 import BASE_DIR, PACKAGE_NAME, PROJECT_NAME # noqa def correcting_imports_in_model_files(file_path): diff --git a/src/generator1/script.py b/src/generator1/script.py index 80b4b80..8374462 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -2,10 +2,16 @@ import os import shutil import subprocess +import sys +from pathlib import Path import yaml -from generator import BASE_DIR, PACKAGE_NAME, PROJECT_NAME -from jinja2 import Environment, FileSystemLoader + +sys.path.append(str(Path(__file__).parent.parent)) + +from jinja2 import Environment, FileSystemLoader # noqa + +from generator1 import BASE_DIR, PACKAGE_NAME, PROJECT_NAME # noqa def extract_functions_and_imports_from_file(file_path) -> None: diff --git a/src/repository/PachcaAPI-0.0.72-py3-none-any.whl b/src/repository/PachcaAPI-0.0.72-py3-none-any.whl deleted file mode 100644 index 3b259d80770e17b79a20fb03f779da2cd3dd6607..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23415 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Ν6Q7pck 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 literal 0 HcmV?d00001 From 0839da9d7c4a4a4cadee14aa7d393edf512fe514 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 19 Mar 2025 18:59:28 +0300 Subject: [PATCH 292/296] small change in generate logic --- src/generator1/openapi.yaml | 2365 +++++++++++++++++++++++++++++++++++ src/generator1/script.py | 167 ++- 2 files changed, 2466 insertions(+), 66 deletions(-) create mode 100644 src/generator1/openapi.yaml diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml new file mode 100644 index 0000000..939326f --- /dev/null +++ b/src/generator1/openapi.yaml @@ -0,0 +1,2365 @@ +openapi: 3.0.3 +info: + title: PachcaAPI - OpenAPI 3.0 + description: Документация к открытому API пачки + version: 3.0.3 +servers: + - url: https://api.pachca.com/api/shared/v1 + +tags: + - name: common methods + description: Everything about common methods + - name: employees + description: Everything about employees + - name: status + description: Everything about + status + - name: tags + description: Everything about + tags + - name: chats and channels + description: Everything about + chats and channels + - name: talk and channel participants + description: Everything about + talk and channel participants + - name: comments + description: Everything about + comments + - name: messages + description: Everything about + messages + - name: reactions to messages + description: Everything about + reactions to messages + - name: reminders + description: Everything about + reminders + +paths: + /custom_properties: + get: + tags: + - common methods + summary: получение списка актульных полей сущности + description: | + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) + operationId: getCommonMethods + parameters: + - name: entity_type + in: query + description: Тип сущности + required: true + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/CommonMethods' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + /uploads: + post: + tags: + - common methods + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + /direct_url: + post: + tags: + - common methods + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. + operationId: getDirectUrl + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + responses: + '201': + description: При безошибочном выполнении запроса тело ответа отсутствует. + /users: + get: + tags: + - employees + summary: получение актуального списка всех сотрудников компании + description: | + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) + operationId: getEmployees + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Employee' + /users/{id}: + get: + tags: + - employees + summary: получение информации о сотруднике + description: | + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + operationId: getEmployee + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Employee' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /profile/status: + get: + tags: + - status + summary: получение информации о своем статусе + description: | + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. + operationId: getStatus + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + put: + tags: + - status + summary: новый статус + description: | + Метод для установки себе нового статуса. + operationId: putStatus + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + status: + $ref: '#/components/schemas/QueryStatus' + responses: + '200': + description: Объект создан + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: + description: Emoji статуса не может содержать значения отличные от Emoji символа + value: + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} + delete: + tags: + - status + summary: удаление своего статуса + description: | + Метод для удаления своего статуса. Параметры запроса отсутствуют. + operationId: delStatus + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствует + content: {} + /group_tags/{id}: + get: + tags: + - tags + summary: получение информации о теге + description: | + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют + operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /group_tags: + get: + tags: + - tags + summary: получение актуального списка тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} + /group_tags/{id}/users: + get: + tags: + - tags + operationId: getTagsEmployees + summary: получение актуального списка сотрудников тега + description: | + Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BaseEmployee' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} + /chats: + post: + tags: + - chats and channels + operationId: createChat + summary: создание новой беседы или канала + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + chat: + $ref: '#/components/schemas/BaseChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + get: + tags: + - chats and channels + operationId: getChats + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) + parameters: + - name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}: + get: + tags: + - chats and channels + operationId: getChat + summary: получение информации о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /chats/{id}/members: + post: + tags: + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса + content: + application/json: + schema: + $ref: '#/components/schemas/MembersChat' + responses: + '204': + description: Пользователи добавлены + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/group_tags: + post: + tags: + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса + content: + application/json: + schema: + $ref: '#/components/schemas/GroupTag' + responses: + '204': + description: Тег(и) добавлен(ы) + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: выход из беседы или канала + description: |- + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствуе + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: + - comments + summary: создание нового треда + description: | + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '201': + description: Тред успешно создан или возвращены данные существующего треда. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Thread' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages: + post: + tags: + - messages + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' + responses: + '201': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - messages + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) + operationId: getListMessage + parameters: + - name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages/{id}: + get: + tags: + - messages + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + description: Successfull + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + put: + tags: + - messages + operationId: editMessage + summary: редактирование сообщения по указанному идентификатору + description: Метод для редактирования сообщения или комментария. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/EditMessages' + responses: + '200': + description: Успешно отредактировано + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages/{id}/reactions: + post: + tags: + - reactions to messages + operationId: postMessageReactions + summary: добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CodeReaction' + responses: + "201": + description: Успешное выполнение запроса, тело ответа отсутствует. + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + user_limit: + description: Превышен лимит уникальных реакций пользователя + value: + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} + unique_limit: + description: Превышен лимит уникальных реакций на сообщение + value: + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} + general_limit: + description: Превышен общий лимит реакций на сообщение + value: + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} + delete: + tags: + - reactions to messages + operationId: deleteMessageReactions + summary: удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + - name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" + responses: + "204": + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - reactions to messages + operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса + parameters: + - name: id + in: path + description: Уникальный идентификатор сообщения + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Список реакций успешно получен. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Reaction' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /tasks: + post: + tags: + - reminders + operationId: createTask + summary: создание нового напоминания + description: | + Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Task' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} +components: + schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code + BaseEmployee: + title: Base Employee + type: object + properties: + id: + type: integer + example: 1 + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + role: + type: string + enum: + - admin + - user + - multi_guest + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + enum: + - confirmed + - sent + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + bot: + type: boolean + description: | + Тип: пользователь (false) или бот (true) + description: Базовый класс сотрудника. + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. + BaseResponse: + title: Base Response + type: object + properties: + Content-Disposition: + type: string + description: Используемый заголовок + default: attachment + acl: + type: string + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + type: object + properties: + status: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + nullable: true + CommonMethods: + title: Common Methods + type: object + description: получение списка актульных полей сущности. + properties: + id: + type: integer + example: 1 + description: Название поля + name: + type: string + example: Дата рождения + description: Идентификатор поля + data_type: + type: string + enum: + - string + - number + - date + - link + example: number + description: тип поля + Errors: + type: object + properties: + errors: + type: array + items: + key: + title: key + type: string + description: Ключ параметра, в котором произошла ошибка + value: + title: value + type: string + description: Значение ключа, которое вызвало ошибку + message: + title: message + type: string + description: Ошибка текстом, который вы можете вывести пользователю + code: + title: code + type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) + payload: + title: payload + type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + BaseThread: + title: Base Thread + type: object + properties: + id: + type: integer + description: Идентификатор поля + chat_id: + type: integer + description: Идентификатор поля чата + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files + type: object + required: + - key + - name + - file_type + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + Files: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Files + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + content: + type: string + description: Текст сообщения + default: Текст сообщения + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type + type: string + enum: + - discussion + - user + - thread + default: discussion + entity_id: + title: Entity Id + type: integer + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false + Message: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + format: date-time + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + description: Размер файла в байтах, отображаемый пользователю + Reaction: + type: object + properties: + user_id: + type: integer + description: | + Идентификатор пользователя, оставившего реакцию. + created_at: + type: string + format: date-time + description: | + Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + code: + type: string + description: | + Emoji символ реакции. + BaseChat: + title: Base Chat + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer + BaseCustomProperties: + title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' + securitySchemes: + bearerAuth: + type: http + scheme: bearer +security: + - bearerAuth: [] diff --git a/src/generator1/script.py b/src/generator1/script.py index 8374462..5c2e455 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -15,7 +15,7 @@ def extract_functions_and_imports_from_file(file_path) -> None: - with open(file_path, encoding="utf-8") as file: + with open(file_path, encoding='utf-8') as file: tree = ast.parse(file.read()) functions = [] @@ -28,18 +28,18 @@ def extract_functions_and_imports_from_file(file_path) -> None: ): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): - module = node.module if node.module else "." + module = node.module if node.module else '.' for alias in node.names: - if module == "typing": - imports.append(f"from typing import {alias.name}") - elif module.startswith("models"): - imports.append(f"from .models import {alias.name}") - elif module == "types": - imports.append(f"from .types import {alias.name}") - elif module == "client_serv": - imports.append(f"from .client_serv import {alias.name}") + if module == 'typing': + imports.append(f'from typing import {alias.name}') + elif module.startswith('models'): + imports.append(f'from .models import {alias.name}') + elif module == 'types': + imports.append(f'from .types import {alias.name}') + elif module == 'client_serv': + imports.append(f'from .client_serv import {alias.name}') else: - imports.append(f"from {module} import {alias.name}") + imports.append(f'from {module} import {alias.name}') return functions, imports @@ -49,7 +49,7 @@ def get_all_api_functions_and_imports(api_dir): all_imports = [] for root, _, files in os.walk(api_dir): for file in files: - if file.endswith(".py"): + if file.endswith('.py'): file_path = os.path.join(root, file) functions, imports = extract_functions_and_imports_from_file( file_path, @@ -60,35 +60,41 @@ def get_all_api_functions_and_imports(api_dir): def get_base_url_from_yaml(openapi_yaml): - with open(os.path.join(BASE_DIR, openapi_yaml), encoding="utf-8") as file: + with open(os.path.join(BASE_DIR, openapi_yaml), encoding='utf-8') as file: data = yaml.safe_load(file) - return data["servers"][0]["url"] + return data['servers'][0]['url'] -api_dir = (os.path.join( - BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'api' -)) -openapi_yaml = "openapi.yaml" +api_dir = os.path.join( + BASE_DIR, + PROJECT_NAME, + PACKAGE_NAME, + 'api', +) +openapi_yaml = 'openapi.yaml' endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) env = Environment( - loader=FileSystemLoader(os.path.join(BASE_DIR, "templates")), + loader=FileSystemLoader(os.path.join(BASE_DIR, 'templates')), ) -client_template = env.get_template("client.py.jinja") +client_template = env.get_template('client.py.jinja') -client_path = (os.path.join( - BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client.py' -)) +client_path = os.path.join( + BASE_DIR, + PROJECT_NAME, + PACKAGE_NAME, + 'client.py', +) -with open(client_path, mode="w", encoding="utf-8") as file: +with open(client_path, mode='w', encoding='utf-8') as file: unique_imports = list(set(imports)) models_imports = sorted( [ model for model in unique_imports if model.startswith( - "from .models", + 'from .models', ) ], ) @@ -97,7 +103,7 @@ def get_base_url_from_yaml(openapi_yaml): model for model in unique_imports if model.startswith( - "from typing import", + 'from typing import', ) ], ) @@ -106,90 +112,119 @@ def get_base_url_from_yaml(openapi_yaml): model for model in unique_imports if model.startswith( - "from .types import", + 'from .types import', ) ], ) other_imports = sorted( list( - set(unique_imports) - set(typing_imports) - - set(types_imports) - set(models_imports), + set(unique_imports) + - set(typing_imports) + - set(types_imports) + - set(models_imports), ), ) if models_imports: models_imports_str = ( - "from .models import (\n " - + ",\n ".join( - [model.split( - "from .models import " - )[-1] for model in models_imports], + 'from .models import (\n ' + + ',\n '.join( + [ + model.split( + 'from .models import ', + )[-1] + for model in models_imports + ], ) - + "\n)" + + '\n)' ) - file.write(models_imports_str + "\n\n") + file.write(models_imports_str + '\n\n') if typing_imports: typing_imports_str = ( - "from typing import (\n " - + ",\n ".join( - [model.split( - "from typing import " - )[-1] for model in typing_imports], + 'from typing import (\n ' + + ',\n '.join( + [ + model.split( + 'from typing import ', + )[-1] + for model in typing_imports + ], ) - + "\n)" + + '\n)' ) - file.write(typing_imports_str + "\n\n") + file.write(typing_imports_str + '\n\n') if types_imports: types_imports_str = ( - "from .types import (\n " - + ",\n ".join( - [model.split( - "from .types import " - )[-1] for model in types_imports], + 'from .types import (\n ' + + ',\n '.join( + [ + model.split( + 'from .types import ', + )[-1] + for model in types_imports + ], ) - + "\n)" + + '\n)' ) - file.write(types_imports_str + "\n\n") + file.write(types_imports_str + '\n\n') if other_imports: - file.write("\n".join(other_imports) + "\n\n") + file.write('\n'.join(other_imports) + '\n\n') file.write(client_template.render(endpoints=endpoints, base_url=base_url)) cli_servis_path = os.path.join( - BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client_serv.py' + BASE_DIR, + PROJECT_NAME, + PACKAGE_NAME, + 'client_serv.py', ) logger_setup_path = os.path.join( - BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'logger_setup.py' + BASE_DIR, + PROJECT_NAME, + PACKAGE_NAME, + 'logger_setup.py', ) source_file_serv = os.path.join( - BASE_DIR, "client_servis.py" + BASE_DIR, + 'client_servis.py', ) shutil.copy(source_file_serv, cli_servis_path) source_file_log = os.path.join( - BASE_DIR, "logger_setup.py" + BASE_DIR, + 'logger_setup.py', ) shutil.copy(source_file_log, logger_setup_path) try: subprocess.run( [ - "black", - (os.path.join( - BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client.py' - )), - "--line-length", - "79", + 'black', + ( + os.path.join( + BASE_DIR, + PROJECT_NAME, + PACKAGE_NAME, + 'client.py', + ) + ), + '--line-length', + '79', ], check=True, ) subprocess.run( [ - "isort", - (os.path.join( - BASE_DIR, PROJECT_NAME, PACKAGE_NAME, 'client.py' - )), + 'isort', + ( + os.path.join( + BASE_DIR, + PROJECT_NAME, + PACKAGE_NAME, + 'client.py', + ) + ), ], ) except subprocess.CalledProcessError as e: - print("Автолинтер не сработал!", e) + print('Автолинтер не сработал!', e) From d04f6a2c815ca289fb662b76d6dbda80e4c15c38 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 19 Mar 2025 19:35:10 +0300 Subject: [PATCH 293/296] add release package --- .../PachcaAPI-0.0.73-py3-none-any.whl | Bin 23506 -> 0 bytes src/repository/PachcaAPI-4.0-py3-none-any.whl | Bin 0 -> 23316 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/repository/PachcaAPI-0.0.73-py3-none-any.whl create mode 100644 src/repository/PachcaAPI-4.0-py3-none-any.whl diff --git a/src/repository/PachcaAPI-0.0.73-py3-none-any.whl b/src/repository/PachcaAPI-0.0.73-py3-none-any.whl deleted file mode 100644 index 57e7f27b4710dfb351e4f10add29bb2be125aead..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23506 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 diff --git a/src/repository/PachcaAPI-4.0-py3-none-any.whl b/src/repository/PachcaAPI-4.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..38f1336cf2cb9c77ece2aaab46e2f2c82d45e404 GIT binary patch literal 23316 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 Date: Wed, 19 Mar 2025 20:05:04 +0300 Subject: [PATCH 294/296] Update README.md --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eb2b126..3cdc3d9 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,31 @@ --- +## 🔨 Установка генератора + +1. **В корне проекта, в файле .env указать:** + - TWINE_USERNAME=<Имя пользвателя сервиса TestPyPI> + - TWINE_API_TOKEN=<Токен пользвателя сервиса TestPyPI> + - TOKEN=<Токен пространства Пачки> + +2. **Установка библиотеки с сериса TestPyPI:** + + ```bash + pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI + ``` + +3. **Запуск генератора и тестов:** + + - run_generate_and_test - запуск генератора и тестов + - run_generator - запуск генератора + - run_test - запуск тестов + +### Примечание: +Пример тест-запросов, которые выполняются командой `run_generate_and_test` и `run_test`, можно найти по пути: +**Дирректория Виртуального Окружения** -> **Дирректория generator1** -> **Файл pachca.py** + +--- + ## 📜 Детали реализации ### 📄 Подготовка OpenAPI-файла: @@ -94,6 +119,12 @@ _src/generator1/_ #### 📁 pachca-api-open-api-3-0-client/ - директория автоматически сгенерированного кода +#### 📄 config_pachca_api.py +- файл имен проекта и пакета + +#### 📄 config_pachca_api.py**** +- вспомогательный файл для запуска генератора и тестов + --- ## 🚀 Установка и использование @@ -315,7 +346,7 @@ _src/generator2/_ 6. **Установка библиотеки с сериса TestPyPI:** ```bash - pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI==0.0.72 + pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ PachcaAPI ``` 7. **Запуск генератора и тестов:** From dbc6d155dd3f35c8abee52ee70d177b3990dadef Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 22 Apr 2025 16:15:04 +0300 Subject: [PATCH 295/296] add new openapi --- openapi.yaml | 2365 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2365 insertions(+) create mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..939326f --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,2365 @@ +openapi: 3.0.3 +info: + title: PachcaAPI - OpenAPI 3.0 + description: Документация к открытому API пачки + version: 3.0.3 +servers: + - url: https://api.pachca.com/api/shared/v1 + +tags: + - name: common methods + description: Everything about common methods + - name: employees + description: Everything about employees + - name: status + description: Everything about + status + - name: tags + description: Everything about + tags + - name: chats and channels + description: Everything about + chats and channels + - name: talk and channel participants + description: Everything about + talk and channel participants + - name: comments + description: Everything about + comments + - name: messages + description: Everything about + messages + - name: reactions to messages + description: Everything about + reactions to messages + - name: reminders + description: Everything about + reminders + +paths: + /custom_properties: + get: + tags: + - common methods + summary: получение списка актульных полей сущности + description: | + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) + operationId: getCommonMethods + parameters: + - name: entity_type + in: query + description: Тип сущности + required: true + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/CommonMethods' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + /uploads: + post: + tags: + - common methods + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + /direct_url: + post: + tags: + - common methods + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. + operationId: getDirectUrl + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + responses: + '201': + description: При безошибочном выполнении запроса тело ответа отсутствует. + /users: + get: + tags: + - employees + summary: получение актуального списка всех сотрудников компании + description: | + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) + operationId: getEmployees + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Employee' + /users/{id}: + get: + tags: + - employees + summary: получение информации о сотруднике + description: | + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + operationId: getEmployee + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Employee' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /profile/status: + get: + tags: + - status + summary: получение информации о своем статусе + description: | + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. + operationId: getStatus + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + put: + tags: + - status + summary: новый статус + description: | + Метод для установки себе нового статуса. + operationId: putStatus + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + status: + $ref: '#/components/schemas/QueryStatus' + responses: + '200': + description: Объект создан + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: + description: Emoji статуса не может содержать значения отличные от Emoji символа + value: + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} + delete: + tags: + - status + summary: удаление своего статуса + description: | + Метод для удаления своего статуса. Параметры запроса отсутствуют. + operationId: delStatus + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствует + content: {} + /group_tags/{id}: + get: + tags: + - tags + summary: получение информации о теге + description: | + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют + operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /group_tags: + get: + tags: + - tags + summary: получение актуального списка тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} + /group_tags/{id}/users: + get: + tags: + - tags + operationId: getTagsEmployees + summary: получение актуального списка сотрудников тега + description: | + Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BaseEmployee' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} + /chats: + post: + tags: + - chats and channels + operationId: createChat + summary: создание новой беседы или канала + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + chat: + $ref: '#/components/schemas/BaseChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + get: + tags: + - chats and channels + operationId: getChats + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) + parameters: + - name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}: + get: + tags: + - chats and channels + operationId: getChat + summary: получение информации о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /chats/{id}/members: + post: + tags: + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса + content: + application/json: + schema: + $ref: '#/components/schemas/MembersChat' + responses: + '204': + description: Пользователи добавлены + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/group_tags: + post: + tags: + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса + content: + application/json: + schema: + $ref: '#/components/schemas/GroupTag' + responses: + '204': + description: Тег(и) добавлен(ы) + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: выход из беседы или канала + description: |- + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствуе + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: + - comments + summary: создание нового треда + description: | + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '201': + description: Тред успешно создан или возвращены данные существующего треда. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Thread' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages: + post: + tags: + - messages + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' + responses: + '201': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - messages + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) + operationId: getListMessage + parameters: + - name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages/{id}: + get: + tags: + - messages + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + description: Successfull + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + put: + tags: + - messages + operationId: editMessage + summary: редактирование сообщения по указанному идентификатору + description: Метод для редактирования сообщения или комментария. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/EditMessages' + responses: + '200': + description: Успешно отредактировано + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages/{id}/reactions: + post: + tags: + - reactions to messages + operationId: postMessageReactions + summary: добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CodeReaction' + responses: + "201": + description: Успешное выполнение запроса, тело ответа отсутствует. + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + user_limit: + description: Превышен лимит уникальных реакций пользователя + value: + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} + unique_limit: + description: Превышен лимит уникальных реакций на сообщение + value: + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} + general_limit: + description: Превышен общий лимит реакций на сообщение + value: + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} + delete: + tags: + - reactions to messages + operationId: deleteMessageReactions + summary: удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + - name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" + responses: + "204": + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - reactions to messages + operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса + parameters: + - name: id + in: path + description: Уникальный идентификатор сообщения + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Список реакций успешно получен. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Reaction' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /tasks: + post: + tags: + - reminders + operationId: createTask + summary: создание нового напоминания + description: | + Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Task' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} +components: + schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code + BaseEmployee: + title: Base Employee + type: object + properties: + id: + type: integer + example: 1 + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + role: + type: string + enum: + - admin + - user + - multi_guest + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + enum: + - confirmed + - sent + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + bot: + type: boolean + description: | + Тип: пользователь (false) или бот (true) + description: Базовый класс сотрудника. + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. + BaseResponse: + title: Base Response + type: object + properties: + Content-Disposition: + type: string + description: Используемый заголовок + default: attachment + acl: + type: string + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + type: object + properties: + status: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + nullable: true + CommonMethods: + title: Common Methods + type: object + description: получение списка актульных полей сущности. + properties: + id: + type: integer + example: 1 + description: Название поля + name: + type: string + example: Дата рождения + description: Идентификатор поля + data_type: + type: string + enum: + - string + - number + - date + - link + example: number + description: тип поля + Errors: + type: object + properties: + errors: + type: array + items: + key: + title: key + type: string + description: Ключ параметра, в котором произошла ошибка + value: + title: value + type: string + description: Значение ключа, которое вызвало ошибку + message: + title: message + type: string + description: Ошибка текстом, который вы можете вывести пользователю + code: + title: code + type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) + payload: + title: payload + type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + BaseThread: + title: Base Thread + type: object + properties: + id: + type: integer + description: Идентификатор поля + chat_id: + type: integer + description: Идентификатор поля чата + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files + type: object + required: + - key + - name + - file_type + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + Files: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Files + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + content: + type: string + description: Текст сообщения + default: Текст сообщения + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type + type: string + enum: + - discussion + - user + - thread + default: discussion + entity_id: + title: Entity Id + type: integer + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false + Message: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + format: date-time + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + description: Размер файла в байтах, отображаемый пользователю + Reaction: + type: object + properties: + user_id: + type: integer + description: | + Идентификатор пользователя, оставившего реакцию. + created_at: + type: string + format: date-time + description: | + Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + code: + type: string + description: | + Emoji символ реакции. + BaseChat: + title: Base Chat + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer + BaseCustomProperties: + title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' + securitySchemes: + bearerAuth: + type: http + scheme: bearer +security: + - bearerAuth: [] From 282779b7d01e8983353e8ceb7096dc789fb23e44 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 22 Apr 2025 16:29:19 +0300 Subject: [PATCH 296/296] delete old openapi --- openapi.yaml | 2365 -------------------------------------------------- 1 file changed, 2365 deletions(-) delete mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml deleted file mode 100644 index 939326f..0000000 --- a/openapi.yaml +++ /dev/null @@ -1,2365 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '201': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/QueryStatus' - responses: - '200': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '204': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '204': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '201': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "201": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: object - properties: - errors: - type: array - items: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - properties: - id: - type: integer - description: Идентификатор поля - chat_id: - type: integer - description: Идентификатор поля чата - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: object - required: - - key - - name - - file_type - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - enum: - - file - - image - CreateEditFiles: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Create&Edit Files - required: - - size - properties: - size: - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Files - properties: - id: - type: integer - description: Идентификатор поля - url: - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - discussion - - user - - thread - default: discussion - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - description: Задаваемые дополнительные поля - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: object - title: Custom Properties - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: []

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∈f-JZCDzn9oSB$Bk`WF#woeAJaHr*F`f<&wHE` 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 Date: Tue, 14 Jan 2025 00:12:57 +0300 Subject: [PATCH 277/296] last changes --- README.md | 723 +++++++++--------- src/builder/README.md | 108 +-- src/generator2/generator2_full/constants.py | 10 - .../models/models_reqBod_createChat.py | 28 - .../models/models_reqBod_createMessage.py | 66 -- .../models/models_reqBod_createTask.py | 45 -- .../models/models_reqBod_editMessage.py | 46 -- .../models/models_reqBod_getDirectUrl.py | 37 - .../models_reqBod_postMembersToChats.py | 14 - .../models_reqBod_postMessageReactions.py | 7 - .../models/models_reqBod_postTagsToChats.py | 10 - .../models/models_reqBod_putStatus.py | 19 - .../models_response_createChatpost201.py | 43 -- .../models_response_createChatpost400.py | 30 - .../models_response_createChatpost422.py | 30 - .../models_response_createMessagepost201.py | 104 --- .../models_response_createMessagepost400.py | 30 - .../models_response_createTaskpost201.py | 66 -- .../models_response_createTaskpost400.py | 30 - .../models_response_createThreadpost200.py | 23 - .../models_response_createThreadpost400.py | 30 - ...esponse_deleteMessageReactionsdelete400.py | 30 - .../models_response_editMessageput200.py | 104 --- .../models_response_editMessageput400.py | 30 - .../models/models_response_getChatget200.py | 43 -- .../models/models_response_getChatget400.py | 30 - .../models/models_response_getChatsget200.py | 45 -- .../models/models_response_getChatsget400.py | 30 - .../models/models_response_getChatsget422.py | 30 - .../models_response_getCommonMethodsget200.py | 23 - .../models_response_getCommonMethodsget400.py | 30 - .../models_response_getEmployeeget200.py | 90 --- .../models_response_getEmployeeget400.py | 30 - .../models_response_getEmployeesget200.py | 92 --- .../models_response_getListMessageget200.py | 106 --- .../models_response_getListMessageget400.py | 30 - ...dels_response_getMessageReactionsget200.py | 20 - ...dels_response_getMessageReactionsget400.py | 30 - .../models_response_getMessageget200.py | 104 --- .../models_response_getMessageget400.py | 30 - .../models/models_response_getStatusget200.py | 19 - .../models/models_response_getTagget200.py | 18 - .../models/models_response_getTagget400.py | 30 - .../models_response_getTagsEmployeesget200.py | 68 -- .../models_response_getTagsEmployeesget400.py | 30 - .../models/models_response_getTagsget200.py | 17 - .../models/models_response_getTagsget400.py | 30 - .../models_response_getUploadspost200.py | 39 - .../models_response_leaveChatdelete400.py | 30 - ...dels_response_postMembersToChatspost400.py | 30 - ...dels_response_postMembersToChatspost422.py | 30 - ...ls_response_postMessageReactionspost400.py | 30 - .../models_response_postTagsToChatspost400.py | 30 - .../models_response_postTagsToChatspost422.py | 30 - .../models/models_response_putStatusput201.py | 19 - .../models/models_response_putStatusput400.py | 30 - .../generator2_full/request_methods.py | 630 --------------- ... pachca_generator1-0.2.3-py3-none-any.whl} | Bin 128920 -> 129056 bytes ... pachca_generator2-0.2.3-py3-none-any.whl} | Bin 137447 -> 137582 bytes 59 files changed, 411 insertions(+), 3125 deletions(-) delete mode 100644 src/generator2/generator2_full/constants.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createChat.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createMessage.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_createTask.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_editMessage.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py delete mode 100644 src/generator2/generator2_full/models/models_reqBod_putStatus.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createChatpost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createMessagepost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost201.py delete mode 100644 src/generator2/generator2_full/models/models_response_createTaskpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost200.py delete mode 100644 src/generator2/generator2_full/models/models_response_createThreadpost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py delete mode 100644 src/generator2/generator2_full/models/models_response_editMessageput200.py delete mode 100644 src/generator2/generator2_full/models/models_response_editMessageput400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getChatsget422.py delete mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeeget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getEmployeesget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getListMessageget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getMessageget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getStatusget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsget200.py delete mode 100644 src/generator2/generator2_full/models/models_response_getTagsget400.py delete mode 100644 src/generator2/generator2_full/models/models_response_getUploadspost200.py delete mode 100644 src/generator2/generator2_full/models/models_response_leaveChatdelete400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py delete mode 100644 src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py delete mode 100644 src/generator2/generator2_full/models/models_response_putStatusput201.py delete mode 100644 src/generator2/generator2_full/models/models_response_putStatusput400.py delete mode 100644 src/generator2/generator2_full/request_methods.py rename src/repository/{pachca_generator1-0.2.2-py3-none-any.whl => pachca_generator1-0.2.3-py3-none-any.whl} (79%) rename src/repository/{pachca_generator2-0.2.2-py3-none-any.whl => pachca_generator2-0.2.3-py3-none-any.whl} (80%) diff --git a/README.md b/README.md index 07eda9c..5bb8ffb 100644 --- a/README.md +++ b/README.md @@ -1,369 +1,354 @@ -# Парсер OpenAPI для мессенджера "Пачка" - -### Библиотека для работы с API мессенджера "Пачка", автоматически генерируемая на Python. 🐍 - -## 🔖 Цели и задачи проекта - -Основная цель проекта — создание инструмента для преобразования спецификации OpenAPI в Python-пакет. 📋 -Этот пакет предоставляет структурированный и удобный интерфейс для взаимодействия с открытым API мессенджера "Пачка". 🌐 - -### ✅ Проект включает: -- **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. -- **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. - -### 🔧 Основные функции: -- **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. -- **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. -- **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. -- **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. - ---- - -## 📜 Детали реализации - -### 📄 Подготовка OpenAPI-файла: -- Формат: JSON или YAML. -- Версия OpenAPI: 3.0. - -**Обязательные секции:** -- `openapi`: Версия файла OpenAPI. -- `info`: Общая информация об API. -- `servers`: Данные о серверах для выполнения запросов. -- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. -- `components`: Схемы данных для структур входных и выходных параметров. - -## 💡 Команда написания спецификации - -- [Денис Лопин](https://github.com/fantyissues) -- [Александр Аполинаров](https://github.com/Alexander-Klp) -- [Александр Тогузов](https://github.com/Imuntouchable) - -### 🔨 Генерация кода: -- **Основной объект**: Центральный класс (`Pachca` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. -- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. -- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. -- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. - ---- - -# 🔧 ***generator1*** - -### 📚 Используемый стек и технологии: -- **Python 3.12+** -- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. -- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. - -## 📂 Структура генератора - -### 🛠️ Основные компоненты -_src/generator1/_ - -#### 🛠️ pachca-api-open-api-3-0-client/client.py -- Автоматически генерируемый файл (появляется после запуска генерации) -- Представлена моделями и методами для работы с API на основе OpenAPI спецификации -- Содержит "динамическую" часть (основной класс для работы с API) после запуска скрипта-генератора -- Передает запрос пользователя в "статическую" часть, преобразовав из формата Python в JSON -- Передает ответ пользователю от "статической" части, преобразовав из формата JSON в Python - -#### 🧩 templates -- Директория хранения основных шаблонов для автоматической генерации - -#### 🔧 client_servis.py -- "Статическая" часть -- Отвечает за отправку/приемку данных на/от сервер(а) -- Полученные данные передает в "динамическую" часть (генерируемую) -- Содержит логику обеспечении безопасности и управления доступом - -#### 💾 script.py -- Создает "динамическую" часть в client.py -- Собирает главный и основной класс Pachca для работы с API - -#### 📜 requirements.txt -- Список зависимостей генератора с версиями - -#### 🧪 pachca.py -- Пример использования сгенерированного API клиента -- Тестовые вызовы различных методов API - -#### 📄 openapi.yaml: -- OpenAPI спецификации API -- Описание эндпоинтов, схем, параметров - -#### 📁 pachca-api-open-api-3-0-client/ -- директория автоматически сгенерированного кода - -#### 🛠️ client_generator.log -- Автоматически генерируемый файл (появляется после запуска тестового скрипта) -- Логгирует асинхронные методы, отражает работу генерации методов - -#### 🛠️ pachca_testresults.log -- Автоматически генерируемый файл (появляется после запуска тестового скрипта) -- Логгирует тестовые функции, отражает полученные данные в тест-запросах - ---- - -## 🚀 Установка и использование - -### 🛠️ Инструкция (работать в папке `generator1` при активированном `venv`): -1. **Создайте файл `.env`** в директории `generator1`, с токеном для работы с API "Пачка". -Пример файла: - ``` - TOKEN=ваштокен - ``` -2. **Создайте и активируйте виртуальное окружение, установите зависимости**: - - Для Linux/gitBash: - ```bash - python3 -m venv venv - source venv/scripts/activate - pip install -r requirements.txt - ``` - - Для Windows cmd: - ```bash - python -m venv venv - .\venv\scripts\activate - pip install -r requirements.txt - ``` -3. **Запустите генерацию клиента:**: - ```bash - python generator.py generate - ``` -4. **Запустите пример запроса**: - ```bash - python generator.py test - ``` - -## 💡 Команда генератора - -- [Алексей Малков](https://github.com/shft1) -- [Владимир Кулаков](https://github.com/VladimirPulse) -- [Даниил Колчак](https://github.com/Daniil-Kolchak) -- [Данил Чирков](https://github.com/Dan1lChirkov) - ---- - -# 🔧 ***generator2*** - -### 📚 Используемый стек и технологии: -- **Python 3.12+** -- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. -- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. -- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. -- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. -- **ruff (0.7.1)**: Для автоматического исправления стилизации кода. -- **black (24.10.0)**: Для автоматического исправления стилизации кода. - -## 📂 Структура генератора - -### 🛠️ Основные компоненты - -_src/generator2/generator2_full_ - -#### 📁 models/ -- models_response_ # Модели ответов API -- models_reqBod_ # Модели запросов API - -#### 🧩 bot.py -- Основной класс для работы с API -- Метакласс RequestMethodsCollector для сбора методов -- Базовая функциональность для HTTP-запросов -- Форматирование URL и параметров запросов - -#### 🔧 constants.py -- Константы клиента -- Константы логгера -- Базовый адрес API, автоматически подтягивается из документации - -#### 🧪 pachca.py -- Пример использования сгенерированного API клиента -- Тестовые вызовы различных методов API - -#### 📁 logger_setup.py -- Подготовка объекта логгера для логирования результатов работы - -#### 🌐 request_methods.py -- Содержит асинхронные методы для работы с API -- Импортирует сгенерированные Pydantic модели -- Реализует логику HTTP-запросов - -_src/generator2/services_ - -#### 🔧 constants.py -- Константы проекта -- Маппинги типов данных -- Пути к файлам -- HTTP методы - -#### 💾 file_writer.py -- Обеспечивает безопасную запись файлов -- Создает необходимые директории -- Управляет генерацией выходных файлов - -#### 📂 yaml_loader.py -- Загрузка YAML файла спецификации OpenAPI -- Создание глобального объекта YAML_DICT - -#### 📁 logger_setup.py -- Подготовка объекта логгера для логирования результатов работы - -_src/generator2/_ - -#### 📝 yaml_processor.py -- Обрабатывает YAML спецификацию -- Генерирует модели запросов и ответов - - Функция get_all_endpoints для извлечения эндпоинтов из YAML документации - - Функция process_endpoints для обработки эндпоинтов и генерации моделей для requestBody и response - -#### 🔗 generate_pydantic_model.py -- Создает модели pydantic для конкретного эндпоинта - - create_model для генерации текста модели pydantic - - create_enum для создания класса Enum - - look_into_schema_new для рекурсивного прохода по модели спецификации и создания всех необходимых моделей - - check_error_field для подмены тайпхинта в модели ошибок API - -#### 🔗 schema_link_processor.py -- Обрабатывает ссылки на схемы в YAML спецификации -- Генерирует модели для ссылок на схемы - - unite_schemas для объединения схем - - load_schema для загрузки схемы по ссылке - - new_replace_ref_with_schema для замены ссылок на схемы - -#### 📜 requirements.txt -- Список зависимостей генератора с версиями - -#### 🛠️ request_methods_generator.py -- Генерация методов для работы с API на основе OpenAPI спецификации -- Функции форматирования URL, параметров и обработки ответов - -#### 📄 openapi.yaml: -- OpenAPI спецификации API -- Описание эндпоинтов, схем, параметров - -#### 🛠️ generator_starter.py -- Основной запуск генерации необходимых файлов для клиента -- Форматтинг и правка сгенерированного кода в автоматическом режиме - ---- - -## 🚀 Установка и использование - -### 🛠️ Инструкция (работать в папке `src` при активированном `venv`): -1. **Создайте файл `.env`** в директории `generator2`, с токеном для работы с API "Пачка". -Пример файла .env.example: - ``` - TOKEN=ваштокен - ``` -2. **Создайте и активируйте виртуальное окружение, установите зависимости**: - - Для Linux/gitBash: - ```bash - python3 -m venv venv - source venv/scripts/activate - pip install -r requirements.txt - ``` - - Для Windows cmd: - ```bash - python -m venv venv - .\venv\scripts\activate - pip install -r requirements.txt - ``` -3. **Запустите генерацию клиента**: - ```bash - python -m generator2.generator_starter - ``` -4. **Запустите пример запроса**: - ```bash - python -m generator2.generator2_full.pachca - ``` - Или перейдите в `generator2` и запустите модуль: - ```bash - cd generator2 - python -m generator2_full.pachca - ``` - -5. **Логирование**: - - В проекте предусмотрено логирование результатов работы генератора и тестовых запросов, логи сохраняются в директроии generator2 - - pachca_log.log - лог работы тестовых запросов. - - Содержит результаты выполнения тестовых запросов, информация о том, что выдал сервер. - - client_generator.log - лог работы генератора клиента. - - Содержит сведения о том, какие пути были обработаны - - Содержит сведения о том, что форматтинг кода завершен - - -## 💡 Команда генератора -- [Алексей Малков](https://github.com/shft1) -- [Дмитрий Костин](https://github.com/k0sdm1) -- [Дмитрий Бурмистров](https://github.com/bura09906) -- [Павел Колесников](https://github.com/Mrclive7406) - ---- - -# 🔧 ***builder*** - -## 🛠️ Инструменты для генерации библиотеки - -### 📋 Порядок действий (работать в папке `builder` при активированном `venv`): - -1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** - - - winget install GnuWin32.Make. - -2. **Создание зависимостей для работы сборки библиотеки:** - - ```bash - pip install requirements_builder.txt - ``` - -3. **Создание зависимостей для библиотеки:** - - ```bash - pipenv install requirements.txt - ``` -4. **Запуск создания и загрузки библиотеки на PyPi при помощи команды:** - - ```bash - make upload - ``` -5. **Установка бибилотеки с тестового PyPi (копирование ссылки):** - - - pip install -i https://test.pypi.org/simple/ pachca-generator1 - - pip install -i https://test.pypi.org/simple/ pachca-generator2 - -## 📂 Структура генератора - -_src/builder/_ - -#### 📜 requirements_builder.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. - -#### 📜 requirements.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. - -#### 📄 Pipfile -- файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. - -#### 🔒 Pipfile.lock -- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. - -#### 🛠️ Makefile -- файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. - -#### 📦 setup_generator1.py, setup_generator2.py -- файл с описанием, каким именно образом будет упакован код для медотов генерации - ---- - -## 💡 Команда упаковки генераторов - -- [Алексей Малков](https://github.com/shft1) -- [Александр Малыгин](https://github.com/SanyM2007) -- [Александр Гора](https://github.com/MrAlexg82) - ---- - -**📄 Документация API**: [Pachca API Documentation](https://crm.pachca.com/dev/getting-started/requests-and-responses/) - ---- +# Парсер OpenAPI для мессенджера "Пачка" + +### Библиотека для работы с API мессенджера "Пачка", автоматически генерируемая на Python. 🐍 + +## 🔖 Цели и задачи проекта + +Основная цель проекта — создание инструмента для преобразования спецификации OpenAPI в Python-пакет. 📋 +Этот пакет предоставляет структурированный и удобный интерфейс для взаимодействия с открытым API мессенджера "Пачка". 🌐 + +### ✅ Проект включает: +- **Конвертацию файлов OpenAPI**: Автоматизация генерации Python-кода, содержащего методы и классы для работы с API. +- **Подготовку Python-пакета**: Упаковка сгенерированного кода для распространения через менеджеры пакетов, такие как pip и poetry. + +### 🔧 Основные функции: +- **Обработка HTTP-запросов**: Сгенерированный код выполняет авторизованные запросы к серверу с использованием токенов. +- **Структуры данных**: Входные и выходные данные представлены в виде Python-классов. +- **Методы для эндпоинтов**: Методы названы в соответствии с эндпоинтами API, что обеспечивает ясность и соответствие. +- **Полная документация**: Сгенерированные классы и методы включают подробные docstring’и, созданные на основе OpenAPI. + +--- + +## 📜 Детали реализации + +### 📄 Подготовка OpenAPI-файла: +- Формат: JSON или YAML. +- Версия OpenAPI: 3.0. + +**Обязательные секции:** +- `openapi`: Версия файла OpenAPI. +- `info`: Общая информация об API. +- `servers`: Данные о серверах для выполнения запросов. +- `paths`: Описание эндпоинтов с параметрами `operationId` и `tags` для генерации методов. +- `components`: Схемы данных для структур входных и выходных параметров. + +## 💡 Команда написания спецификации + +- [Денис Лопин](https://github.com/fantyissues) +- [Александр Аполинаров](https://github.com/Alexander-Klp) +- [Александр Тогузов](https://github.com/Imuntouchable) + +### 🔨 Генерация кода: +- **Основной объект**: Центральный класс (`Pachca` - для 1 генератора, `Bot` - для 2 генератора), инициализируемый токеном авторизации. +- **Методы эндпоинтов**: Генерируются на основе параметра `operationId` из OpenAPI. +- **Модели данных**: Определены с использованием `pydantic` для входных и выходных схем. +- **Обработка ошибок**: Пользовательские исключения для API-ошибок на основе описания OpenAPI. + +--- + +# 🔧 ***generator1*** + +### 📚 Используемый стек и технологии: +- **Python 3.12+** +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi-python-client (0.22.0)**: Для автоматической генерации клиентского кода на основе OpenAPI спецификаций. + +## 📂 Структура генератора + +### 🛠️ Основные компоненты +_src/generator1/_ + +#### 🛠️ pachca-api-open-api-3-0-client/client.py +- Автоматически генерируемый файл (появляется после запуска генерации) +- Представлена моделями и методами для работы с API на основе OpenAPI спецификации +- Содержит "динамическую" часть (основной класс для работы с API) после запуска скрипта-генератора +- Передает запрос пользователя в "статическую" часть, преобразовав из формата Python в JSON +- Передает ответ пользователю от "статической" части, преобразовав из формата JSON в Python + +#### 🧩 templates +- Директория хранения основных шаблонов для автоматической генерации + +#### 🔧 client_servis.py +- "Статическая" часть +- Отвечает за отправку/приемку данных на/от сервер(а) +- Полученные данные передает в "динамическую" часть (генерируемую) +- Содержит логику обеспечении безопасности и управления доступом + +#### 💾 script.py +- Создает "динамическую" часть в client.py +- Собирает главный и основной класс Pachca для работы с API + +#### 📜 requirements.txt +- Список зависимостей генератора с версиями + +#### 🧪 pachca.py +- Пример использования сгенерированного API клиента +- Тестовые вызовы различных методов API + +#### 📄 openapi.yaml: +- OpenAPI спецификации API +- Описание эндпоинтов, схем, параметров + +#### 📁 pachca-api-open-api-3-0-client/ +- директория автоматически сгенерированного кода + +--- + +## 🚀 Установка и использование + +### 🛠️ Инструкция (работать в папке `generator1` при активированном `venv`): +1. **Создайте файл `.env`** в директории `generator1`, с токеном для работы с API "Пачка". +Пример файла: + ``` + TOKEN=ваштокен + ``` +2. **Создайте и активируйте виртуальное окружение, установите зависимости**: + - Для Linux/gitBash: + ```bash + python3 -m venv venv + source venv/scripts/activate + pip install -r requirements.txt + ``` + - Для Windows cmd: + ```bash + python -m venv venv + .\venv\scripts\activate + pip install -r requirements.txt + ``` +3. **Запустите генерацию клиента:**: + ```bash + python generator.py generate + ``` +4. **Запустите пример запроса**: + ```bash + python generator.py test + ``` + +## 💡 Команда генератора + +- [Алексей Малков](https://github.com/shft1) +- [Владимир Кулаков](https://github.com/VladimirPulse) +- [Даниил Колчак](https://github.com/Daniil-Kolchak) +- [Данил Чирков](https://github.com/Dan1lChirkov) + +--- + +# 🔧 ***generator2*** + +### 📚 Используемый стек и технологии: +- **Python 3.12+** +- **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. +- **pydantic (2.10.4)**: Для определения моделей данных ввода и вывода. +- **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. +- **openapi3-parser (1.1.19)**: Для парсинга OpenAPI спецификации. +- **ruff (0.7.1)**: Для автоматического исправления стилизации кода. +- **black (24.10.0)**: Для автоматического исправления стилизации кода. + +## 📂 Структура генератора + +### 🛠️ Основные компоненты + +_src/generator2/generator2_full_ + +#### 📁 models/ +- models_response_ # Модели ответов API +- models_reqBod_ # Модели запросов API + +#### 🧩 bot.py +- Основной класс для работы с API +- Метакласс RequestMethodsCollector для сбора методов +- Базовая функциональность для HTTP-запросов +- Форматирование URL и параметров запросов + +#### 🔧 constants.py +- Константы клиента +- Константы логгера + +#### 🧪 pachca.py +- Пример использования сгенерированного API клиента +- Тестовые вызовы различных методов API + +#### 📁 logger_setup.py +- Подготовка объекта логгера для логирования результатов работы + +#### 🌐 request_methods.py +- Содержит асинхронные методы для работы с API +- Импортирует сгенерированные Pydantic модели +- Реализует логику HTTP-запросов + +_src/generator2/services_ + +#### 🔧 constants.py +- Константы проекта +- Маппинги типов данных +- Пути к файлам +- HTTP методы + +#### 💾 file_writer.py +- Обеспечивает безопасную запись файлов +- Создает необходимые директории +- Управляет генерацией выходных файлов + +#### 📂 yaml_loader.py +- Загрузка YAML файла спецификации OpenAPI +- Создание глобального объекта YAML_DICT + +#### 📁 logger_setup.py +- Подготовка объекта логгера для логирования результатов работы + +_src/generator2/_ + +#### 📝 yaml_processor.py +- Обрабатывает YAML спецификацию +- Генерирует модели запросов и ответов + - Функция get_all_endpoints для извлечения эндпоинтов из YAML документации + - Функция process_endpoints для обработки эндпоинтов и генерации моделей для requestBody и response + +#### 🔗 generate_pydantic_model.py +- Создает модели pydantic для конкретного эндпоинта + - create_model для генерации текста модели pydantic + - create_enum для создания класса Enum + - look_into_schema_new для рекурсивного прохода по модели спецификации и создания всех необходимых моделей + - check_error_field для подмены тайпхинта в модели ошибок API + +#### 🔗 schema_link_processor.py +- Обрабатывает ссылки на схемы в YAML спецификации +- Генерирует модели для ссылок на схемы + - unite_schemas для объединения схем + - load_schema для загрузки схемы по ссылке + - new_replace_ref_with_schema для замены ссылок на схемы + +#### 📜 requirements.txt +- Список зависимостей генератора с версиями + +#### 🛠️ request_methods_generator.py +- Генерация методов для работы с API на основе OpenAPI спецификации +- Функции форматирования URL, параметров и обработки ответов + +#### 📄 openapi.yaml: +- OpenAPI спецификации API +- Описание эндпоинтов, схем, параметров + +#### 🛠️ generator_starter.py +- Основной запуск генерации необходимых файлов для клиента +- Форматтинг и правка сгенерированного кода в автоматическом режиме + +--- + +## 🚀 Установка и использование + +### 🛠️ Инструкция (работать в папке `src` при активированном `venv`): +1. **Создайте файл `.env`** в директории `generator2`, с токеном для работы с API "Пачка". +Пример файла .env.example: + ``` + TOKEN=ваштокен + ``` +2. **Создайте и активируйте виртуальное окружение, установите зависимости**: + - Для Linux/gitBash: + ```bash + python3 -m venv venv + source venv/scripts/activate + pip install -r requirements.txt + ``` + - Для Windows cmd: + ```bash + python -m venv venv + .\venv\scripts\activate + pip install -r requirements.txt + ``` +3. **Запустите генерацию клиента**: + ```bash + python -m generator2.generator_starter + ``` +4. **Запустите пример запроса**: + ```bash + python -m generator2.generator2_full.pachca + ``` + Или перейдите в `generator2` и запустите модуль: + ```bash + cd generator2 + python -m generator2_full.pachca + ``` + +## 💡 Команда генератора +- [Алексей Малков](https://github.com/shft1) +- [Дмитрий Костин](https://github.com/k0sdm1) +- [Дмитрий Бурмистров](https://github.com/bura09906) +- [Павел Колесников](https://github.com/Mrclive7406) + +--- + +# 🔧 ***builder*** + +## 🛠️ Инструменты для генерации библиотеки + +### 📋 Порядок действий (работать в папке `builder` при активированном `venv`): + +1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** + + - winget install GnuWin32.Make. + +2. **Создание зависимостей для работы сборки библиотеки:** + + ```bash + pip install requirements_builder.txt + ``` + +3. **Создание зависимостей для библиотеки:** + + ```bash + pipenv install requirements.txt + ``` + +4. **В папке проекта pachca_code_gen_team2 в файле .env указать:** + - PACKAGE_VERSION=<Версия пакета> + - TWINE_USERNAME=<Имя пользвателя сервиса TestPyPI> + - TWINE_API_TOKEN=<Токен пользвателя сервиса TestPyPI> + +4. **Запуск создания и загрузки библиотеки на серис TestPyPI при помощи команды:** + + ```bash + make upload + ``` +5. **Установка бибилотеки с сериса TestPyPI:** + + - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator1 + - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator2 + +## 📂 Структура генератора + +_src/builder/_ + +#### 📜 requirements_builder.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. + +#### 📜 requirements.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. + +#### 📄 Pipfile +- файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. + +#### 🔒 Pipfile.lock +- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. + +#### 🛠️ Makefile +- файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. + +#### 📦 setup_generator1.py, setup_generator2.py +- файл с описанием, каким именно образом будет упакован код для медотов генерации + +--- + +## 💡 Команда упаковки генераторов + +- [Алексей Малков](https://github.com/shft1) +- [Александр Малыгин](https://github.com/SanyM2007) +- [Александр Гора](https://github.com/MrAlexg82) + +--- + +**📄 Документация API**: [Pachca API Documentation](https://crm.pachca.com/dev/getting-started/requests-and-responses/) + +--- diff --git a/src/builder/README.md b/src/builder/README.md index 190e5f6..c9a3b53 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -1,52 +1,58 @@ -# 🔧 ***builder*** - -## 🛠️ Инструменты для генерации библиотеки - -### 📋 Порядок действий (работать в папке `builder` при активированном `venv`): - -1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** - - - winget install GnuWin32.Make. - -2. **Создание зависимостей для работы сборки библиотеки:** - - ```bash - pip install requirements_builder.txt - ``` - -3. **Создание зависимостей для библиотеки:** - - ```bash - pipenv install requirements.txt - ``` -4. **Запуск создания и загрузки библиотеки на PyPi при помощи команды:** - - ```bash - make upload - ``` -5. **Установка бибилотеки с тестового PyPi (копирование ссылки):** - - - pip install -i https://test.pypi.org/simple/ pachca-generator1 - - pip install -i https://test.pypi.org/simple/ pachca-generator2 - -## 📂 Структура генератора - -_src/builder/_ - -#### 📜 requirements_builder.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. - -#### 📜 requirements.txt -- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. - -#### 📄 Pipfile -- файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. - -#### 🔒 Pipfile.lock -- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. - -#### 🛠️ Makefile -- файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. - -#### 📦 setup_generator1.py, setup_generator2.py +# 🔧 ***builder*** + +## 🛠️ Инструменты для генерации библиотеки + +### 📋 Порядок действий (работать в папке `builder` при активированном `venv`): + +1. **Для запуска MakeFile командой make из VSCode нужно установить через PowerShell или cmd:** + + - winget install GnuWin32.Make. + +2. **Создание зависимостей для работы сборки библиотеки:** + + ```bash + pip install requirements_builder.txt + ``` + +3. **Создание зависимостей для библиотеки:** + + ```bash + pipenv install requirements.txt + ``` + +4. **В папке проекта pachca_code_gen_team2 в файле .env указать:** + - PACKAGE_VERSION=<Версия пакета> + - TWINE_USERNAME=<Имя пользвателя сервиса TestPyPI> + - TWINE_API_TOKEN=<Токен пользвателя сервиса TestPyPI> + +4. **Запуск создания и загрузки библиотеки на серис TestPyPI при помощи команды:** + + ```bash + make upload + ``` +5. **Установка бибилотеки с сериса TestPyPI:** + + - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator1 + - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator2 + +## 📂 Структура генератора + +_src/builder/_ + +#### 📜 requirements_builder.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы упаковщика библиотеки. + +#### 📜 requirements.txt +- файл, содержащий список пакетов или библиотек, необходимых для работы над библиотек. + +#### 📄 Pipfile +- файл, используемый виртуальной средой Pipenv для управления зависимостями библиотек. + +#### 🔒 Pipfile.lock +- файл в формате JSON хранит контрольные суммы пакетов, которые устанавливаются в проект, что даёт гарантию, что развёрнутые на разных машинах окружения будут идентичны друг другу. + +#### 🛠️ Makefile +- файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. + +#### 📦 setup_generator1.py, setup_generator2.py - файл с описанием, каким именно образом будет упакован код для медотов генерации \ No newline at end of file diff --git a/src/generator2/generator2_full/constants.py b/src/generator2/generator2_full/constants.py deleted file mode 100644 index 7055256..0000000 --- a/src/generator2/generator2_full/constants.py +++ /dev/null @@ -1,10 +0,0 @@ -# Client constants -URL = 'https://api.pachca.com/api/shared/v1' -PARAM_NAME_SORT = 'sort' -PARAM_NAME_SORT_FIELD = 'sort_field' -TOKEN_TYPE = 'Bearer' - -# Logger constants -LOG_FILE_NAME = 'pachca_log.log' -MAX_FILE_SIZE = 1 * 1024 * 1024 # 1 MB -BACKUP_COUNT = 3 diff --git a/src/generator2/generator2_full/models/models_reqBod_createChat.py b/src/generator2/generator2_full/models/models_reqBod_createChat.py deleted file mode 100644 index 089e9c2..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createChat.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Chat(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - - -class Createchat(BaseModel): - chat: Optional[Chat] = Field( - None, - description="Собранный объект параметров создаваемой беседы или канала", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createMessage.py b/src/generator2/generator2_full/models/models_reqBod_createMessage.py deleted file mode 100644 index a6280ed..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createMessage.py +++ /dev/null @@ -1,66 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - size: int = Field( - ..., description="Размер файла в байтах, отображаемый пользователю", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Message(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - skip_invite_mentions: Optional[bool] = Field( - None, description="No docstring provided", - ) - link_preview: Optional[bool] = Field( - None, description="No docstring provided", - ) - - -class Createmessage(BaseModel): - message: Optional[Message] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_createTask.py b/src/generator2/generator2_full/models/models_reqBod_createTask.py deleted file mode 100644 index ce503e3..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_createTask.py +++ /dev/null @@ -1,45 +0,0 @@ -from enum import IntEnum, StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - value: Optional[str] = Field(None, description="Значение поля") - - -class enum_kind(StrEnum): - call = "call" - meeting = "meeting" - reminder = "reminder" - event = "event" - email = "email" - - -class enum_priority(IntEnum): - priority_1 = 1 - priority_2 = 2 - priority_3 = 3 - - -class Task(BaseModel): - kind: enum_kind = Field(..., description="Тип напоминания") - content: str = Field(..., description="Описание напоминания") - due_at: str = Field( - ..., description="Срок выполнения напоминания (ISO-8601)", - ) - priority: Optional[enum_priority] = Field( - None, - description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", - ) - performer_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов пользователей", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="No docstring provided", - ) - - -class Createtask(BaseModel): - task: Optional[Task] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_reqBod_editMessage.py b/src/generator2/generator2_full/models/models_reqBod_editMessage.py deleted file mode 100644 index 8db9faf..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_editMessage.py +++ /dev/null @@ -1,46 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - size: int = Field( - ..., description="Размер файла в байтах, отображаемый пользователю", - ) - - -class Message(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - - -class Editmessage(BaseModel): - message: Optional[Message] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py b/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py deleted file mode 100644 index a4f35e7..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_getDirectUrl.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Getdirecturl(BaseModel): - Content_Disposition: Optional[str] = Field( - None, - description="Используемый заголовок", - alilas="Content-Disposition", - ) - acl: Optional[str] = Field(None, description="Уровень безопасности") - policy: Optional[str] = Field( - None, description="Уникальный policy для загрузки файла", - ) - x_amz_credential: Optional[str] = Field( - None, - description="x-amz-credential для загрузки файла", - alilas="x-amz-credential", - ) - x_amz_algorithm: Optional[str] = Field( - None, description="Используемый алгоритм", alilas="x-amz-algorithm", - ) - x_amz_date: Optional[str] = Field( - None, - description="Уникальный x-amz-date для загрузки файла", - alilas="x-amz-date", - ) - x_amz_signature: Optional[str] = Field( - None, - description="Уникальная подпись для загрузки файла", - alilas="x-amz-signature", - ) - key: Optional[str] = Field( - None, description="Уникальный ключ для загрузки файла", - ) - file: Optional[str] = Field(None, description="Адрес для загрузки файла") diff --git a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py b/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py deleted file mode 100644 index 59b7182..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postMembersToChats.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Postmemberstochats(BaseModel): - member_ids: List[int] = Field( - ..., - description="Массив идентификаторов пользователей, которые станут участниками", - ) - silent: Optional[bool] = Field( - None, - description="Не создавать в чате системное сообщение о добавлении участника", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py b/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py deleted file mode 100644 index ba69294..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postMessageReactions.py +++ /dev/null @@ -1,7 +0,0 @@ -from pydantic import BaseModel, Field - - -class Postmessagereactions(BaseModel): - code: str = Field( - ..., description="Emoji в строковом формате для добавления реакции.", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py b/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py deleted file mode 100644 index f935dd3..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_postTagsToChats.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List - -from pydantic import BaseModel, Field - - -class Posttagstochats(BaseModel): - group_tag_ids: List[int] = Field( - ..., - description="Массив идентификаторов тегов, которые станут участниками", - ) diff --git a/src/generator2/generator2_full/models/models_reqBod_putStatus.py b/src/generator2/generator2_full/models/models_reqBod_putStatus.py deleted file mode 100644 index 0e19d8f..0000000 --- a/src/generator2/generator2_full/models/models_reqBod_putStatus.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class Putstatus(BaseModel): - status: Optional[Status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost201.py b/src/generator2/generator2_full/models/models_response_createChatpost201.py deleted file mode 100644 index 289211b..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost201.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseCreatechatPost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createChatpost400.py b/src/generator2/generator2_full/models/models_response_createChatpost400.py deleted file mode 100644 index 3d5be37..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatechatPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createChatpost422.py b/src/generator2/generator2_full/models/models_response_createChatpost422.py deleted file mode 100644 index 9ee79aa..0000000 --- a/src/generator2/generator2_full/models/models_response_createChatpost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatechatPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost201.py b/src/generator2/generator2_full/models/models_response_createMessagepost201.py deleted file mode 100644 index a7da269..0000000 --- a/src/generator2/generator2_full/models/models_response_createMessagepost201.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseCreatemessagePost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createMessagepost400.py b/src/generator2/generator2_full/models/models_response_createMessagepost400.py deleted file mode 100644 index b484245..0000000 --- a/src/generator2/generator2_full/models/models_response_createMessagepost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatemessagePost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost201.py b/src/generator2/generator2_full/models/models_response_createTaskpost201.py deleted file mode 100644 index 749ca91..0000000 --- a/src/generator2/generator2_full/models/models_response_createTaskpost201.py +++ /dev/null @@ -1,66 +0,0 @@ -from enum import IntEnum, StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - value: Optional[str] = Field(None, description="Значение поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - - -class enum_kind(StrEnum): - call = "call" - meeting = "meeting" - reminder = "reminder" - event = "event" - email = "email" - - -class enum_priority(IntEnum): - priority_1 = 1 - priority_2 = 2 - priority_3 = 3 - - -class Data(BaseModel): - kind: enum_kind = Field(..., description="Тип напоминания") - content: str = Field(..., description="Описание напоминания") - due_at: str = Field( - ..., description="Срок выполнения напоминания (ISO-8601)", - ) - priority: Optional[enum_priority] = Field( - None, - description="Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно)", - ) - performer_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов пользователей", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="No docstring provided", - ) - id: Optional[int] = Field( - None, description="Идентификатор созданного напоминания", - ) - user_id: Optional[int] = Field( - None, description="Идентификатор пользователя-создателя", - ) - status: Optional[str] = Field(None, description="Статус напоминания") - created_at: Optional[str] = Field( - None, description="Дата и время создания", - ) - - -class ResponseCreatetaskPost201(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createTaskpost400.py b/src/generator2/generator2_full/models/models_response_createTaskpost400.py deleted file mode 100644 index 7b83d43..0000000 --- a/src/generator2/generator2_full/models/models_response_createTaskpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatetaskPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost200.py b/src/generator2/generator2_full/models/models_response_createThreadpost200.py deleted file mode 100644 index 93e2199..0000000 --- a/src/generator2/generator2_full/models/models_response_createThreadpost200.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред.", - ) - message_chat_id: Optional[int] = Field( - None, description="Идентификатор чата сообщения.", - ) - updated_at: Optional[str] = Field( - None, - description="Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", - ) - - -class ResponseCreatethreadPost200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_createThreadpost400.py b/src/generator2/generator2_full/models/models_response_createThreadpost400.py deleted file mode 100644 index aab3648..0000000 --- a/src/generator2/generator2_full/models/models_response_createThreadpost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseCreatethreadPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py b/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py deleted file mode 100644 index c80757d..0000000 --- a/src/generator2/generator2_full/models/models_response_deleteMessageReactionsdelete400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseDeletemessagereactionsDelete400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_editMessageput200.py b/src/generator2/generator2_full/models/models_response_editMessageput200.py deleted file mode 100644 index 2daa577..0000000 --- a/src/generator2/generator2_full/models/models_response_editMessageput200.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseEditmessagePut200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_editMessageput400.py b/src/generator2/generator2_full/models/models_response_editMessageput400.py deleted file mode 100644 index cb7e60d..0000000 --- a/src/generator2/generator2_full/models/models_response_editMessageput400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseEditmessagePut400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatget200.py b/src/generator2/generator2_full/models/models_response_getChatget200.py deleted file mode 100644 index 26c9d0a..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatget200.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseGetchatGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getChatget400.py b/src/generator2/generator2_full/models/models_response_getChatget400.py deleted file mode 100644 index 5cf12e6..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget200.py b/src/generator2/generator2_full/models/models_response_getChatsget200.py deleted file mode 100644 index 68c2eec..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget200.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - name: str = Field(..., description="Название") - member_ids: Optional[List[int]] = Field( - None, - description="Массив идентификаторов пользователей, которые станут участниками", - ) - group_tag_ids: Optional[List[int]] = Field( - None, description="Массив идентификаторов тегов, участников", - ) - channel: Optional[bool] = Field( - None, description="Тип: беседа (по умолчанию, false) или канал (true)", - ) - public: Optional[bool] = Field( - None, - description="Доступ: закрытый (по умолчанию, false) или открытый (true)", - ) - id: Optional[int] = Field( - None, description="Идентификатор беседы или канала", - ) - owner_id: Optional[int] = Field( - None, - description="Идентификатор пользователя, создавшего беседу или канал", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - last_message_at: Optional[str] = Field( - None, - description="Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - meet_room_url: Optional[str] = Field( - None, description="Ссылка на Видеочат", - ) - - -class ResponseGetchatsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget400.py b/src/generator2/generator2_full/models/models_response_getChatsget400.py deleted file mode 100644 index 0893c6b..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getChatsget422.py b/src/generator2/generator2_full/models/models_response_getChatsget422.py deleted file mode 100644 index 89c7937..0000000 --- a/src/generator2/generator2_full/models/models_response_getChatsget422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetchatsGet422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py deleted file mode 100644 index 9c132b3..0000000 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget200.py +++ /dev/null @@ -1,23 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Название поля") - name: Optional[str] = Field(None, description="Идентификатор поля") - data_type: Optional[enum_data_type] = Field(None, description="тип поля") - - -class ResponseGetcommonmethodsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py b/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py deleted file mode 100644 index f2ae8ba..0000000 --- a/src/generator2/generator2_full/models/models_response_getCommonMethodsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetcommonmethodsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py b/src/generator2/generator2_full/models/models_response_getEmployeeget200.py deleted file mode 100644 index a798652..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget200.py +++ /dev/null @@ -1,90 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class User_status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - user_status: Optional[User_status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) - title: Optional[str] = Field(None, description="Должность") - created_at: Optional[str] = Field( - None, - description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - time_zone: Optional[str] = Field( - None, description="Часовой пояс пользователя", - ) - image_url: Optional[str] = Field( - None, description="Ссылка на скачивание аватарки", - ) - - -class ResponseGetemployeeGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py b/src/generator2/generator2_full/models/models_response_getEmployeeget400.py deleted file mode 100644 index a22237a..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeeget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetemployeeGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getEmployeesget200.py deleted file mode 100644 index 6f24174..0000000 --- a/src/generator2/generator2_full/models/models_response_getEmployeesget200.py +++ /dev/null @@ -1,92 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class User_status(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - user_status: Optional[User_status] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) - title: Optional[str] = Field(None, description="Должность") - created_at: Optional[str] = Field( - None, - description="Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - time_zone: Optional[str] = Field( - None, description="Часовой пояс пользователя", - ) - image_url: Optional[str] = Field( - None, description="Ссылка на скачивание аватарки", - ) - - -class ResponseGetemployeesGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget200.py b/src/generator2/generator2_full/models/models_response_getListMessageget200.py deleted file mode 100644 index c187528..0000000 --- a/src/generator2/generator2_full/models/models_response_getListMessageget200.py +++ /dev/null @@ -1,106 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseGetlistmessageGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getListMessageget400.py b/src/generator2/generator2_full/models/models_response_getListMessageget400.py deleted file mode 100644 index 9bc441d..0000000 --- a/src/generator2/generator2_full/models/models_response_getListMessageget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetlistmessageGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py deleted file mode 100644 index ce9da6a..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageReactionsget200.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - user_id: Optional[int] = Field( - None, description="Идентификатор пользователя, оставившего реакцию.", - ) - created_at: Optional[str] = Field( - None, - description="Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ.", - ) - code: Optional[str] = Field(None, description="Emoji символ реакции.") - - -class ResponseGetmessagereactionsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py b/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py deleted file mode 100644 index 369fcdf..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageReactionsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetmessagereactionsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getMessageget200.py b/src/generator2/generator2_full/models/models_response_getMessageget200.py deleted file mode 100644 index 92d3d71..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageget200.py +++ /dev/null @@ -1,104 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Buttons(BaseModel): - text: Optional[str] = Field(None, description="No docstring provided") - url: Optional[str] = Field(None, description="No docstring provided") - data: Optional[str] = Field(None, description="No docstring provided") - - -class enum_file_type(StrEnum): - file = "file" - image = "image" - - -class Files(BaseModel): - key: str = Field( - ..., - description="Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях)", - ) - name: str = Field( - ..., - description="Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением)", - ) - file_type: enum_file_type = Field(..., description="No docstring provided") - id: Optional[int] = Field(None, description="No docstring provided") - url: Optional[str] = Field( - None, description="Прямая временная ссылка на скачивание файла", - ) - - -class Thread(BaseModel): - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - - -class Forwarding(BaseModel): - original_message_id: Optional[int] = Field( - None, description="Идентификатор оригинального сообщения", - ) - original_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - author_id: Optional[int] = Field( - None, - description="Идентификатор чата, в котором находится оригинальное сообщение", - ) - original_created_at: Optional[int] = Field( - None, - description="Дата и время создания оригинального сообщения (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ", - ) - original_thread_id: Optional[int] = Field( - None, - description="Идентификатор треда, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - original_thread_parent_chat_id: Optional[int] = Field( - None, - description="Идентификатор чата сообщения, к которому был создан тред, в котором находится оригинальное сообщение. Возвращается как null, если оригинальное сообщение не является комментарием в треде.", - ) - - -class enum_entity_type(StrEnum): - discussion = "discussion" - user = "user" - thread = "thread" - - -class Data(BaseModel): - content: str = Field(..., description="Текст сообщения") - buttons: Optional[List[List[Buttons]]] = Field( - None, description="No docstring provided", - ) - entity_type: Optional[enum_entity_type] = Field( - None, description="No docstring provided", - ) - entity_id: int = Field(..., description="No docstring provided") - parent_message_id: Optional[int] = Field( - None, - description="Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом.", - ) - id: Optional[int] = Field(None, description="No docstring provided") - chat_id: Optional[int] = Field(None, description="No docstring provided") - user_id: Optional[int] = Field(None, description="No docstring provided") - created_at: Optional[str] = Field( - None, description="No docstring provided", - ) - files: Optional[List[Files]] = Field( - None, description="No docstring provided", - ) - thread: Optional[Thread] = Field(None, description="No docstring provided") - forwarding: Optional[Forwarding] = Field( - None, description="No docstring provided", - ) - - -class ResponseGetmessageGet200(BaseModel): - data: Optional[Data] = Field(None, description="No docstring provided") diff --git a/src/generator2/generator2_full/models/models_response_getMessageget400.py b/src/generator2/generator2_full/models/models_response_getMessageget400.py deleted file mode 100644 index 9c51172..0000000 --- a/src/generator2/generator2_full/models/models_response_getMessageget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGetmessageGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getStatusget200.py b/src/generator2/generator2_full/models/models_response_getStatusget200.py deleted file mode 100644 index 0d09a11..0000000 --- a/src/generator2/generator2_full/models/models_response_getStatusget200.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class ResponseGetstatusGet200(BaseModel): - data: Optional[Data] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget200.py b/src/generator2/generator2_full/models/models_response_getTagget200.py deleted file mode 100644 index ef7a650..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagget200.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор тега") - name: Optional[str] = Field(None, description="Название тега") - users_count: Optional[int] = Field( - None, description="Количество сотрудников, которые имеют этот тег", - ) - - -class ResponseGettagGet200(BaseModel): - data: Optional[Data] = Field( - None, - description="Для получения тега вам необходимо знать его id и указать его в URL запроса.", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagget400.py b/src/generator2/generator2_full/models/models_response_getTagget400.py deleted file mode 100644 index a3b9fe0..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py deleted file mode 100644 index d835b3a..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget200.py +++ /dev/null @@ -1,68 +0,0 @@ -from enum import StrEnum -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class enum_data_type(StrEnum): - string = "string" - number = "number" - date = "date" - link = "link" - - -class Custom_properties(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор поля") - name: Optional[str] = Field(None, description="Название поля") - data_type: Optional[enum_data_type] = Field( - None, description="Тип поля (string, number, date или link)", - ) - value: Optional[str] = Field(None, description="Значение") - - -class enum_role(StrEnum): - admin = "admin" - user = "user" - multi_guest = "multi_guest" - - -class enum_invite_status(StrEnum): - confirmed = "confirmed" - sent = "sent" - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор пользователя") - first_name: Optional[str] = Field(None, description="Имя") - last_name: Optional[str] = Field(None, description="Фамилия") - nickname: Optional[str] = Field(None, description="Имя пользователя") - email: Optional[str] = Field(None, description="Электронная почта") - phone_number: Optional[str] = Field(None, description="Телефон") - department: Optional[str] = Field(None, description="Департамент") - role: Optional[enum_role] = Field( - None, - description="Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость)", - ) - suspended: Optional[bool] = Field( - None, - description="Деактивация пользователя. При значении true пользователь является деактивированным.", - ) - invite_status: Optional[enum_invite_status] = Field( - None, - description="Статус приглашения: confirmed (принято), sent (отправлено)", - ) - list_tags: Optional[List[str]] = Field( - None, description="Массив тегов, привязанных к сотруднику", - ) - custom_properties: Optional[List[Custom_properties]] = Field( - None, description="Дополнительные поля сотрудника", - ) - bot: Optional[bool] = Field( - None, description="Тип: пользователь (false) или бот (true)", - ) - - -class ResponseGettagsemployeesGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py b/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py deleted file mode 100644 index a7c67de..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsEmployeesget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagsemployeesGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget200.py b/src/generator2/generator2_full/models/models_response_getTagsget200.py deleted file mode 100644 index a6f0b4b..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsget200.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import List, Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - id: Optional[int] = Field(None, description="Идентификатор тега") - name: Optional[str] = Field(None, description="Название тега") - users_count: Optional[int] = Field( - None, description="Количество сотрудников, которые имеют этот тег", - ) - - -class ResponseGettagsGet200(BaseModel): - data: Optional[List[Data]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getTagsget400.py b/src/generator2/generator2_full/models/models_response_getTagsget400.py deleted file mode 100644 index 0015a61..0000000 --- a/src/generator2/generator2_full/models/models_response_getTagsget400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseGettagsGet400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_getUploadspost200.py b/src/generator2/generator2_full/models/models_response_getUploadspost200.py deleted file mode 100644 index 0d31122..0000000 --- a/src/generator2/generator2_full/models/models_response_getUploadspost200.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class ResponseGetuploadsPost200(BaseModel): - Content_Disposition: Optional[str] = Field( - None, - description="Используемый заголовок", - alilas="Content-Disposition", - ) - acl: Optional[str] = Field(None, description="Уровень безопасности") - policy: Optional[str] = Field( - None, description="Уникальный policy для загрузки файла", - ) - x_amz_credential: Optional[str] = Field( - None, - description="x-amz-credential для загрузки файла", - alilas="x-amz-credential", - ) - x_amz_algorithm: Optional[str] = Field( - None, description="Используемый алгоритм", alilas="x-amz-algorithm", - ) - x_amz_date: Optional[str] = Field( - None, - description="Уникальный x-amz-date для загрузки файла", - alilas="x-amz-date", - ) - x_amz_signature: Optional[str] = Field( - None, - description="Уникальная подпись для загрузки файла", - alilas="x-amz-signature", - ) - key: Optional[str] = Field( - None, description="Уникальный ключ для загрузки файла", - ) - direct_url: Optional[str] = Field( - None, description="Адрес для загрузки файла", - ) diff --git a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py b/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py deleted file mode 100644 index 3e430a1..0000000 --- a/src/generator2/generator2_full/models/models_response_leaveChatdelete400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponseLeavechatDelete400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py deleted file mode 100644 index 5dd1dbd..0000000 --- a/src/generator2/generator2_full/models/models_response_postMembersToChatspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmemberstochatsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py b/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py deleted file mode 100644 index bdf933f..0000000 --- a/src/generator2/generator2_full/models/models_response_postMembersToChatspost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmemberstochatsPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py b/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py deleted file mode 100644 index 0d305f2..0000000 --- a/src/generator2/generator2_full/models/models_response_postMessageReactionspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePostmessagereactionsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py deleted file mode 100644 index e0385a7..0000000 --- a/src/generator2/generator2_full/models/models_response_postTagsToChatspost400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePosttagstochatsPost400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py b/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py deleted file mode 100644 index 8b157bf..0000000 --- a/src/generator2/generator2_full/models/models_response_postTagsToChatspost422.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePosttagstochatsPost422(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput201.py b/src/generator2/generator2_full/models/models_response_putStatusput201.py deleted file mode 100644 index db4d1ca..0000000 --- a/src/generator2/generator2_full/models/models_response_putStatusput201.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel, Field - - -class Data(BaseModel): - emoji: Optional[str] = Field(None, description="Emoji символ статуса") - title: Optional[str] = Field(None, description="Текст статуса") - expires_at: Optional[str] = Field( - None, - description="Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен.", - ) - - -class ResponsePutstatusPut201(BaseModel): - data: Optional[Data] = Field( - None, - description="Статус. Возвращается как null, если статус не установлен.", - ) diff --git a/src/generator2/generator2_full/models/models_response_putStatusput400.py b/src/generator2/generator2_full/models/models_response_putStatusput400.py deleted file mode 100644 index 74a54e1..0000000 --- a/src/generator2/generator2_full/models/models_response_putStatusput400.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any, Dict, List, Optional - -from pydantic import BaseModel, Field - - -class Errors(BaseModel): - key: Optional[str] = Field( - None, description="Ключ параметра, в котором произошла ошибка", - ) - value: Optional[Any] = Field( - None, description="Значение ключа, которое вызвало ошибку", - ) - message: Optional[str] = Field( - None, - description="Ошибка текстом, который вы можете вывести пользователю", - ) - code: Optional[str] = Field( - None, - description="Внутренний код ошибки (коды ошибок представлены в описании каждого метода)", - ) - payload: Optional[Dict] = Field( - None, - description="Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода)", - ) - - -class ResponsePutstatusPut400(BaseModel): - errors: Optional[List[Errors]] = Field( - None, description="No docstring provided", - ) diff --git a/src/generator2/generator2_full/request_methods.py b/src/generator2/generator2_full/request_methods.py deleted file mode 100644 index c4bca53..0000000 --- a/src/generator2/generator2_full/request_methods.py +++ /dev/null @@ -1,630 +0,0 @@ -from .models.models_reqBod_createChat import Createchat -from .models.models_reqBod_createMessage import Createmessage -from .models.models_reqBod_createTask import Createtask -from .models.models_reqBod_editMessage import Editmessage -from .models.models_reqBod_getDirectUrl import Getdirecturl -from .models.models_reqBod_postMembersToChats import Postmemberstochats -from .models.models_reqBod_postMessageReactions import Postmessagereactions -from .models.models_reqBod_postTagsToChats import Posttagstochats -from .models.models_reqBod_putStatus import Putstatus -from .models.models_response_createChatpost201 import ResponseCreatechatPost201 -from .models.models_response_createChatpost422 import ResponseCreatechatPost422 -from .models.models_response_createMessagepost201 import ( - ResponseCreatemessagePost201, -) -from .models.models_response_createMessagepost400 import ( - ResponseCreatemessagePost400, -) -from .models.models_response_createTaskpost201 import ResponseCreatetaskPost201 -from .models.models_response_createTaskpost400 import ResponseCreatetaskPost400 -from .models.models_response_createThreadpost200 import ( - ResponseCreatethreadPost200, -) -from .models.models_response_createThreadpost400 import ( - ResponseCreatethreadPost400, -) -from .models.models_response_deleteMessageReactionsdelete400 import ( - ResponseDeletemessagereactionsDelete400, -) -from .models.models_response_editMessageput200 import ResponseEditmessagePut200 -from .models.models_response_editMessageput400 import ResponseEditmessagePut400 -from .models.models_response_getChatget200 import ResponseGetchatGet200 -from .models.models_response_getChatget400 import ResponseGetchatGet400 -from .models.models_response_getChatsget200 import ResponseGetchatsGet200 -from .models.models_response_getChatsget422 import ResponseGetchatsGet422 -from .models.models_response_getCommonMethodsget200 import ( - ResponseGetcommonmethodsGet200, -) -from .models.models_response_getCommonMethodsget400 import ( - ResponseGetcommonmethodsGet400, -) -from .models.models_response_getEmployeeget200 import ResponseGetemployeeGet200 -from .models.models_response_getEmployeeget400 import ResponseGetemployeeGet400 -from .models.models_response_getEmployeesget200 import ( - ResponseGetemployeesGet200, -) -from .models.models_response_getListMessageget200 import ( - ResponseGetlistmessageGet200, -) -from .models.models_response_getListMessageget400 import ( - ResponseGetlistmessageGet400, -) -from .models.models_response_getMessageReactionsget200 import ( - ResponseGetmessagereactionsGet200, -) -from .models.models_response_getMessageReactionsget400 import ( - ResponseGetmessagereactionsGet400, -) -from .models.models_response_getMessageget200 import ResponseGetmessageGet200 -from .models.models_response_getMessageget400 import ResponseGetmessageGet400 -from .models.models_response_getStatusget200 import ResponseGetstatusGet200 -from .models.models_response_getTagget200 import ResponseGettagGet200 -from .models.models_response_getTagget400 import ResponseGettagGet400 -from .models.models_response_getTagsEmployeesget200 import ( - ResponseGettagsemployeesGet200, -) -from .models.models_response_getTagsEmployeesget400 import ( - ResponseGettagsemployeesGet400, -) -from .models.models_response_getTagsget200 import ResponseGettagsGet200 -from .models.models_response_getTagsget400 import ResponseGettagsGet400 -from .models.models_response_getUploadspost200 import ResponseGetuploadsPost200 -from .models.models_response_leaveChatdelete400 import ( - ResponseLeavechatDelete400, -) -from .models.models_response_postMembersToChatspost422 import ( - ResponsePostmemberstochatsPost422, -) -from .models.models_response_postMessageReactionspost400 import ( - ResponsePostmessagereactionsPost400, -) -from .models.models_response_postTagsToChatspost422 import ( - ResponsePosttagstochatsPost422, -) -from .models.models_response_putStatusput201 import ResponsePutstatusPut201 -from .models.models_response_putStatusput400 import ResponsePutstatusPut400 - - -class RequestMethods: - - async def get_client(self): - pass - - async def format_url(self): - pass - - async def filter_query_params(self): - pass - - async def get_common_methods( - self, entity_type: str = None, - ) -> ResponseGetcommonmethodsGet200: - """получение списка актульных полей сущности - - Метод для получения актуального списка дополнительных полей участников и - напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в - URL (например, /custom_properties?entity_type=User) - """ - client = await self.get_client() - async with client: - url = "/custom_properties" - query_params = await self.filter_query_params( - entity_type=entity_type, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetcommonmethodsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetcommonmethodsGet400.model_validate_json( - response.text, - ) - return None - - async def get_uploads(self) -> ResponseGetuploadsPost200: - """получения подписи и ключа для загрузки файла - - Данный метод необходимо использовать для загрузки каждого файла. Данный метод - позволяет получить уникальный набор параметров для загрузки файла. Параметры - запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/uploads" - response = await client.post(url) - if response.is_success: - return ResponseGetuploadsPost200.model_validate_json( - response.text, - ) - return None - - async def get_direct_url(self, data: Getdirecturl): - """(полученный в ответе на запрос /uploads) загрузка файла - - Данный метод не требует авторизации. Получив все параметры, вам необходимо - сделать POST запрос в формате multipart/form-data на адрес, который был указан - в поле direct_url, отправив полученные параметры и сам файл. - """ - client = await self.get_client() - async with client: - url = "/direct_url" - response = await client.post(url, json=data.model_dump()) - return - - async def get_employees( - self, per: int = None, page: int = None, query: str = None, - ) -> ResponseGetemployeesGet200: - """получение актуального списка всех сотрудников компании - - Метод для получения актуального списка сотрудников вашей компании. Тело запроса - отсутствует, параметры передаются в URL (например, - /users?per=50&page=2&query=example.com) - """ - client = await self.get_client() - async with client: - url = "/users" - query_params = await self.filter_query_params( - per=per, page=page, query=query, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetemployeesGet200.model_validate_json( - response.text, - ) - return None - - async def get_employee(self, id: int) -> ResponseGetemployeeGet200: - """получение информации о сотруднике - - Метод для получения информации о сотруднике. Для получения сотрудника вам - необходимо знать его id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/users/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetemployeeGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetemployeeGet400.model_validate_json( - response.text, - ) - return None - - async def get_status(self) -> ResponseGetstatusGet200: - """получение информации о своем статусе - - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.get(url) - if response.is_success: - return ResponseGetstatusGet200.model_validate_json( - response.text, - ) - return None - - async def put_status(self, data: Putstatus) -> ResponsePutstatusPut201: - """новый статус - - Метод для установки себе нового статуса. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.put(url, json=data.model_dump()) - if response.is_success: - return ResponsePutstatusPut201.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponsePutstatusPut400.model_validate_json( - response.text, - ) - return None - - async def del_status(self): - """удаление своего статуса - - Метод для удаления своего статуса. Параметры запроса отсутствуют. - """ - client = await self.get_client() - async with client: - url = "/profile/status" - response = await client.delete(url) - return - - async def get_tag(self, id: int) -> ResponseGettagGet200: - """получение информации о теге - - Метод для получения информации о теге. Названия тегов являются уникальными в - компании. Для получения тега вам необходимо знать его id и указать его в URL - запроса. Параметры запроса отсутствуют - """ - client = await self.get_client() - async with client: - url = await self.format_url("/group_tags/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGettagGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGettagGet400.model_validate_json(response.text) - return None - - async def get_tags( - self, per: int = None, page: int = None, - ) -> ResponseGettagsGet200: - """получение актуального списка тегов сотрудников - - Метод для получения актуального списка тегов сотрудников. Названия тегов - являются уникальными в компании. Тело запроса отсутствует, параметры передаются - в URL (например, /group_tags?per=10&page=2) - """ - client = await self.get_client() - async with client: - url = "/group_tags" - query_params = await self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGettagsGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGettagsGet400.model_validate_json(response.text) - return None - - async def get_tags_employees( - self, id: int, per: int = None, page: int = None, - ) -> ResponseGettagsemployeesGet200: - """получение актуального списка сотрудников тега - - Метод для получения актуального списка сотрудников тега. Идентификатор тега, - список сотрудников которого необходимо получить, и другие параметры передаются - в URL (например, /group_tags/877650/users?per=3&page=2) - """ - client = await self.get_client() - async with client: - url = await self.format_url("/group_tags/{id}/users", {"id": id}) - query_params = await self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGettagsemployeesGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGettagsemployeesGet400.model_validate_json( - response.text, - ) - return None - - async def get_chats( - self, - sort_field: str = "id", - sort: str = "desc", - per: int = None, - page: int = None, - availability: str = None, - last_message_at_after: str = None, - last_message_at_before: str = None, - ) -> ResponseGetchatsGet200: - """получение списка бесед и каналов - - Метод для получения списка бесед и каналов по заданным параметрам. Тело - запроса отсутствует, параметры передаются в URL (например, - /chats?per=2&sort[id]=desc) - """ - client = await self.get_client() - async with client: - url = "/chats" - query_params = await self.filter_query_params( - sort_field=sort_field, - sort=sort, - per=per, - page=page, - availability=availability, - last_message_at_after=last_message_at_after, - last_message_at_before=last_message_at_before, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetchatsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetchatsGet422.model_validate_json( - response.text, - ) - return None - - async def create_chat(self, data: Createchat) -> ResponseCreatechatPost201: - """создание новой беседы или канала - - Метод для создания новой беседы или нового канала. При создании беседы или - канала вы автоматически становитесь участником. - """ - client = await self.get_client() - async with client: - url = "/chats" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatechatPost201.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatechatPost422.model_validate_json( - response.text, - ) - return None - - async def get_chat(self, id: int) -> ResponseGetchatGet200: - """получение информации о беседе или канале - - Получения информации о беседе или канале. Для получения беседы или канала вам - необходимо знать её id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/chats/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetchatGet200.model_validate_json(response.text) - if response.is_client_error: - return ResponseGetchatGet400.model_validate_json(response.text) - return None - - async def post_members_to_chats(self, data: Postmemberstochats, id: int): - """добавление пользователей в состав участников - - Метод для добавления пользователей в состав участников беседы или канала. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/chats/{id}/members", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePostmemberstochatsPost422.model_validate_json( - response.text, - ) - return None - - async def post_tags_to_chats(self, data: Posttagstochats, id: int): - """добавление тегов в состав участников беседы или канала - - Метод для добавления тегов в состав участников беседы или канала. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/chats/{id}/group_tags", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePosttagstochatsPost422.model_validate_json( - response.text, - ) - return None - - async def leave_chat(self, id: int): - """выход из беседы или канала - - Метод для самостоятельного выхода из беседы или канала. Параметры запроса - отсутствуют/ - """ - client = await self.get_client() - async with client: - url = await self.format_url("/chats/{id}/leave", {"id": id}) - response = await client.delete(url) - if response.is_client_error: - return ResponseLeavechatDelete400.model_validate_json( - response.text, - ) - return None - - async def create_thread(self, id: int) -> ResponseCreatethreadPost200: - """создание нового треда - - Метод для создания нового треда к сообщению. Если у сообщения уже был создан - тред, то в ответе вернётся информация об уже созданном ранее треде. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/messages/{id}/thread", {"id": id}) - response = await client.post(url) - if response.is_success: - return ResponseCreatethreadPost200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatethreadPost400.model_validate_json( - response.text, - ) - return None - - async def get_list_message( - self, chat_id: int = None, per: int = None, page: int = None, - ) -> ResponseGetlistmessageGet200: - """получение списка сообщений чата - - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены в - порядке убывания даты отправки (то есть, сначала будут идти последние сообщения - чата). Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, - /messages?chat_id=198&per=3) - """ - client = await self.get_client() - async with client: - url = "/messages" - query_params = await self.filter_query_params( - chat_id=chat_id, per=per, page=page, - ) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetlistmessageGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetlistmessageGet400.model_validate_json( - response.text, - ) - return None - - async def create_message( - self, data: Createmessage, - ) -> ResponseCreatemessagePost201: - """создание нового сообщения - - Метод для отправки сообщения в беседу или канал, личного сообщения пользователю - или комментария в тред. При использовании entity_type: "discussion" (или - просто без указания entity_type) допускается отправка любого chat_id в поле - entity_id. То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его - идентификатору или личное сообщение по идентификатору пользователя. Для - отправки личного сообщения пользователю создавать чат не требуется. Достаточно - указать entity_type: "user" и идентификатор пользователя. Чат будет создан - автоматически, если между вами ещё не было переписки. Между двумя - пользователями может быть только один личный чат. - """ - client = await self.get_client() - async with client: - url = "/messages" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatemessagePost201.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatemessagePost400.model_validate_json( - response.text, - ) - return None - - async def get_message(self, id: int) -> ResponseGetmessageGet200: - """получение информации о сообщении - - Метод для получения информации о сообщении. Для получения сообщения вам - необходимо знать его id и указать его в URL запроса. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/messages/{id}", {"id": id}) - response = await client.get(url) - if response.is_success: - return ResponseGetmessageGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetmessageGet400.model_validate_json( - response.text, - ) - return None - - async def edit_message( - self, data: Editmessage, id: int, - ) -> ResponseEditmessagePut200: - """редактирование сообщения по указанному идентификатору - - Метод для редактирования сообщения или комментария. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/messages/{id}", {"id": id}) - response = await client.put(url, json=data.model_dump()) - if response.is_success: - return ResponseEditmessagePut200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseEditmessagePut400.model_validate_json( - response.text, - ) - return None - - async def get_message_reactions( - self, id: int, per: int = None, page: int = None, - ) -> ResponseGetmessagereactionsGet200: - """получение актуального списка реакций - - Метод для получения актуального списка реакций на сообщение. Идентификатор - сообщения, список реакций на которое необходимо получить, передается в URL - (например, /messages/7231942/reactions). Количество возвращаемых сущностей и - страница выборки указываются в теле запроса - """ - client = await self.get_client() - async with client: - url = await self.format_url("/messages/{id}/reactions", {"id": id}) - query_params = await self.filter_query_params(per=per, page=page) - response = await client.get(url, params=query_params) - if response.is_success: - return ResponseGetmessagereactionsGet200.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseGetmessagereactionsGet400.model_validate_json( - response.text, - ) - return None - - async def post_message_reactions( - self, data: Postmessagereactions, id: int, - ): - """добавление реакции - - Метод для добавления реакции на сообщение. **Лимиты реакций:** - Каждый - пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - Сообщение может иметь - не более 1000 реакций. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/messages/{id}/reactions", {"id": id}) - response = await client.post(url, json=data.model_dump()) - if response.is_client_error: - return ResponsePostmessagereactionsPost400.model_validate_json( - response.text, - ) - return None - - async def delete_message_reactions(self, id: int, code: str = None): - """удаление реакции - - Метод для удаления реакции на сообщение. Удалить можно только те реакции, - которые были поставлены авторизованным пользователем. - """ - client = await self.get_client() - async with client: - url = await self.format_url("/messages/{id}/reactions", {"id": id}) - query_params = await self.filter_query_params(code=code) - response = await client.delete(url, params=query_params) - if response.is_client_error: - return ResponseDeletemessagereactionsDelete400.model_validate_json( - response.text, - ) - return None - - async def create_task(self, data: Createtask) -> ResponseCreatetaskPost201: - """создание нового напоминания - - Метод для создания нового напоминания. При создании напоминания обязательным - условием является указания типа напоминания: звонок, встреча, простое - напоминание, событие или письмо. При этом не требуется дополнительное описание - - вы просто создадите напоминание с соответствующим текстом. Если вы укажите - описание напоминания - то именно оно и станет текстом напоминания. У - напоминания должны быть ответственные, если их не указывать - ответственным - назначаетесь вы. - """ - client = await self.get_client() - async with client: - url = "/tasks" - response = await client.post(url, json=data.model_dump()) - if response.is_success: - return ResponseCreatetaskPost201.model_validate_json( - response.text, - ) - if response.is_client_error: - return ResponseCreatetaskPost400.model_validate_json( - response.text, - ) - return None diff --git a/src/repository/pachca_generator1-0.2.2-py3-none-any.whl b/src/repository/pachca_generator1-0.2.3-py3-none-any.whl similarity index 79% rename from src/repository/pachca_generator1-0.2.2-py3-none-any.whl rename to src/repository/pachca_generator1-0.2.3-py3-none-any.whl index ebcdcd062dd3b1b809dd97338fcb41c5503faeca..f710791a5de48b0fd4aae61beab110990478103b 100644 GIT binary patch delta 12880 zcmY*=by$^8)GaS5B`qM`A&7u<3rKf&Nq0Ag?hX$PN_R=isdXVHG|fk7h{;Lk4uKjvJqU|U?+6RQu=kYDSiyo036jvssRE(#xY!|d zf;^uV#4O_*c=mGpWc`dgpAnv?Pb5_#)8bOZ&$OA`+%w(D$p*F^1+WuZy-^_ZDasRY z5VX?NefAsHZF{yOzhJ|@Rxf1K{MQ#0G~@?V0x3Nm_+$cjlW=H;3(>%vH$7{*td*ZN zc#dPwIZhSCZU<4?H(rI6{;i`LE>)NYhja9qlLy zC#@C#Tob;v9Y7Q@?M)Cxf>ihHv%s?ZdpZ#u6qFJ+ScnQ>NEmN{tI_Xad2Ty#;2I){ z8Z3NH&M_wPOnXmXKq5HK%tB_RW*eSMf}1CL_M%+QgnsVc{7t6=2p$S*9UL16FxEV* z#y+2@=-*$T{i*i~p9>j3xPgQjJpAz7$-~Js^mAeCAAZe^z(7ISBP9ryGl2hY00`ie z4FI!-;^Nnf=k>&Mps~BMUwzS&puk@z})kIjS3Kh^jPmh2gD;iSGhdqD@E|{ zl*z&;d{|}xYwrPw^-3QBs%L)>c3|t-U!MmEcphvE03(no@Q+WxE+kT>FmV4&q724&>T>F*4SAA z&%Y>O27BNLQXQcKP!DMYJmUgvK!`@y{}w6O1L%9!$oT-c&jT|*K<~NffgoV(^vs*KS=z&r`vfidmIC)l%#4E6;}L)z5!G4ND6WF zNam4*D;m{ru(+l@Ay+&D20=wmE%{=lE3Ue}h{N#2$rTb`#TxFMcOW0Q_-KDI_D9AX zq9Oj4wChZfQo-o$XkM`!=qJ)h6MkxM+E8ozA^_eRye zLBZ6l?~=%_R=l=pqWD#+S8KhB6dB=yK8iTy+&Yd@)`anClk~602~|((n$I#)1TliDSwrUPN22>*U$ZRN=ip#Gqj%C|Snpe23lMoS z-_JFv)QCGtwf(X&US+rHb7*-W9h#bI6f>ABc5hR;cu>9irV}DsO<;MuV-tPq3O$Bu zF{J7vIY2;RrcsNf+YPdqmQFXf0f^3jSq9hNM5`c2eLY?tteVlbEW^*1`bvO(>Dt<4 z+}P-BtW&$3_Yh$>ukGaUy=zAl%bd$(4vMjG(S6(UHeYK<>5MVwH(Q#EY>B3&GnPme zi7-D$_-tkEoA&|sGp&_osg{-|Qv>{$Wx?B8Hf8#E{9d*GA2>ib?Fwlb8QwqD;jAli ztasl2*!P(uaVrg;4t{YxC0ggE(>`Y7+1_Rj&5&<$QPon5Uxd?pyYm?>NvfM zY3pKF5KGVDKNfui6*|5aZ-ElwkMx+RF(dIIMrF_DYEcxaL~aS#31~K~d>{HW5J&^- zvu-8qyQ>QYE^wGW)9ouCo`eIbG-nTdtuPsalRs}!IUgFmYx7jQoo z`bJOw5~Hu?Rjmy%$8vqjH%J`q7r#J^ba*9K7x#8_jbqLcbRv|WcXN03M*0=;0U4v& zQbdy=A9rApHM$l;KXt7NrYMrm?pb6{wOEe48lfp4cQDr@d|M0h7eS;Oe9lO)vDWB_ zZ!nSBIFZ%bN0Mb6L&`f6>{)$b%HwIf<`XZXdEZW7WDlJ4SC05r)ucu?uMu2xc4%qc z+9Q^F<;=KAL9T0+1biXe%2_`k|+%yGCXXuWaKcP~U8>WkO~0OgN4M$@%enH#g~_ z#JM=Ark`|<{)Feh5iS$VqFzYR$C=Ax*Apta{?;e!1nNl;E^f}gE;Q+&ZwcPpxK>;& zEac)PE9Rl()CNE4v$o$UgixQPczrq)^zTp{{1hJ)B-fL^rE3a1gO*lpB7a^!IeZ$4UN;8V<7>y}rrMYw9U)7O?!W z`AhjloL!f9r!Sp~Rl>&>u`AC&@oxm|h6$t-7h%k93hU;4GFqf1L4;0rAtvW`b|G&h zt0yQ%r^Z~I`SV(7W@VwAaN}UCF=mvN^owG8;uS&7eND5H+c$hEG^0_6dIQ`uSFtCN z)FUvM>lDy{S^gT7kTIWJHH^oM@FT*dJ6af$e@1zaNQXJOOuuuMbMVCl%%`G_xF$NS z1+bZ{@9eM66zfNk!#xw}1~9WdYUCQt`iHhgqD@n^=~hkjyS3W(w#Q=yTk=D`Exg@M z@f^@RLlaU_hZRb9?9;)75r#E0RIFT%aX}1H%lAx{8nNSW-sBF__;QSHLxd5=yL2nx zY&+S9hdTl_j7$4S5Ep3M`K#GQ?6gltrBHkdR!tI}7auw56~BFTXStHbH8&Z@;?)f& zhSrHM)E8}JNAo5`tt!}t)_a!#I{u~}R6Z5$j1UV|4SaFVybz&M1l z@w_4(CCSM|dv$*2P^yzY2GbbM_X*0dE_T+vugSQ{d5A;TQ8RCvUlbQ0(YMtEsMCxgsz zJmfC1A%OskCRyqu|Jo!B)|OzWw$xbMZ+6w6*9R-fxjbh zrfCmV!2Ia2Ep|sb&j3YK_WNm^nO1UA?QONJqN5d*JLZVAG5t?BjWg*&Ma~j$MPpc8 z8}KOBU{^c~EvWpVGY2&;$|+76n5Lz=+st~ZcNNHbi_V1bVK)qm_K1^W?*)Wr{)1-l$I_{8$u7_IT z0Gk2eCLFYJJmq0mGiOs2h!u_OId?qyP`c(YyZwiZL$0=`4guqk>*lj8c8Jo3kP|-* z?f$l}mokBvM^z7B(m5x)h$iUcYmWq@#0Z5#URu7CyrV&BAr9BLAe*rCQ1T5zWNp36 zgCEp`795KQ20v~bDawV&tdYJUH%732Wm!2=NFzUzFGX}smP`-hdHqL)jgCEq>916v zDpo{?svv`{0%p(UdxxC{Cs&rAfOq43nX&$dt5DPK++@ZR4yytcl#N4>@5m+LcgbLM zN|?LUb!`5)Pd;)}h;JU5M*@)EC0qpYa?NN=+OyC;P%;K)(nWqU>nRC;S5KE=Z6KSe zbA6~pponoGSW-p48A(JZLz=-mrAYRPxBKnu+Z)+<5!Q4lcd9sVKD#wu&jjTQQr(0Q zG5_l>N*DeptofrNKWNxEP}gcfk8?~isnB8U{i5t(Tz70x_X-&l*7@s!nlY+V>U{B} z6V?81$1P#M31ZZx9Qh5w@S-#oB}6`KLK~W*ce317MSs8Yi_4xN(k%cv=w?i0jW4P{lQ63=&T%dZ_iA1wi9Qf<|S}@TXTfbuf7` z#M-ff_P%uW-ATxL1u7=C`Uv(g+wdfcT2<}*)u5lW)YY?BIab^bCug!^5gx2r z)R(^G+kN74_qE$5cnaU8sxjV`c59H;k_ zF&{5D3)4b6drcR+kE_^V)>LZJ^hWM*^e$qg$akF#+nAqrAxRAti*fS-wX1lxW@g!l`ERD$||Q zU2&Y!j)(@>g0gI{bF#mfRB_TWUq0WfTmK*`C=OATsj%S!g5@8I_O*nD9AQf6biL>MK;oR-)uM`yF>G$uY^R-@>R%)G+8*8a`~5T`p2pB-^fh z6xL#J?fI}6YV^6F@n4b7l~OBk$Vb|q*@wI`Y(~-iZrRaUDru$RnqSif7m>9QkSJ>F zd8gs|4PRx~yswt+_!(~CIe$KQZ^j=K?gNr^iKog_HvXnQ@0cu{l$wg8JXYAeSECLe z!q?XVfI@j+`TsIfQ4L=vvHU}g%X&vw4_6Vpmnd?{4NuHhwsLVeeunclDV?|ft6b%G zvM8J~7<3^4!$hVCbn%?0Q)>Ab!$cc{v!DzCsfP&e+<3-#1?<>G)yb4l#xKIzn-$!d z8Zk8CoyV`uhl%mUdbhLO$Qk)W-JxtkKKtb7X@hvqI73WaITbHAwvjn}LaEbLOh$~J z5TvTMJ+qhm3d|!ZC%&CqOB$(X2PqORbw{T}$?6)9ke~B^+zA(>ZN29`RrxSN^{({O znM&=F$52h@hGEskZtSR!;u{98wQgsljrN-!lwGsV4#f{}FeJuT?4HKmU(+4>VcW!& zpcz1c#Fle%LGKZ_9>_-Tis={175f#{Yo!PHqDOK5dPAEo1q(L5s~sizLS8iOg^Z9_ z6->CYwiJj_>E`x5zhA?qx#%Zz>N0b{KChaXw*S}ZnbVde`qBWkZJ2$PUrj}g3Gb7P zxujQRt&%Peqa|sgZ#j*+bm-m}cB|9%))m=+dk8EZ(UMUGudsR5BK1 zrf22VAy}yS1Z3~y(OyjpEgnWb?%pqZ^g|7jiEhjt4Hhw`%7GN9S2nHLRQk4*Y=s#z z6&}At#Efm92%diSWtgPQP~gF06%Wnc+$y@OUdjfzn1t3 znmWS77^ir3uNBL$anh{NifHbIG2vDeEVJWTH0&swgg9C3fkV@(eHxeHgm;&5+~iZ9 zZExG8qG%s#do^ij%^ zh}1IeM&O!KVKa0_O;+^^v8pVmKIKz5NU4mZBN`@9V0BTodpOIyM2Hj_=g-%9E3Vnq zYoe#Nx zV{n`wWA~d7l<{LT%VT>C7dZ-a-HrFfq_+|0eK=O^$T;l9+v+2`aN2**mCQ;pkw+bH zjr^=T6zpX}Gk@b545PwJ>@xnKk=VKk)@E*yO5q-F8XNc?s_5DwNJzs?G_ZqD6m!9= zCDDsf5=dyvN{>1BR%gS85el_7CE70h;4kZqP z6W!~MZdvbQrUZI&#}>Eq9i|qSCsS~-t!|Uc;~9Y(=xlR33HxznSzv&e!^i!0KX0F@ zT(8OH@*zoTe4Qec_4p6X-9=6CDI!aF%1_jO-rv7|GZlmhDJyM_0ogBZ6|GlY53kAwWDOgLjjH&x|InC>grVRRKq?<)8`A$ew zzdmKjI!}nrS$xlIJCMHXnjdRHaEUQnaRTeqy*Y>glP-8_KGUV?+lPs4VYIUa4zCnb zUll@}%rgckC+AVGSM^$GIQ2MpQ$)eyEd0GoxegQCtbM2J1`D^}i*(wNoVoH>x=WvI_-%ws7JrP?#4U{^ z9&a!Xyq>{DyZxbe^TTRc%NO}dqz-|^1)#E0hT!(3^oG#@Ms0(SMdlm9Wr zw&VRYpRbHFw%;_`x+<7-HC@?WuG*I6Al8NZO#D_?CafL(M?enfae%0!E$pBh|NWm_ z6Q{&-YK6{Fo7fy(q|p#gckhmSWORRc`;G;-Rg)kNT)sw?GyRZ1d}x;2RLhO%=MW0&4rJZD%e@O= z4BneXtAL?|y;NN3JB-F%Vp}lwNv3y&C<(APepZ_qQW|(+YR{x!Us@k-Z<FNbVAC^)$DYkNBt^{7^Vi5L<=x{Ch+>FND-- zI`7KMr=jAsjnO=RK%<%caRDt*drRGy}oR{hNJO5~~jgqLU~{_^xd z@go{^fSS5L^njvAO!?&&2R#o$8TKnX&7V8m&CBc`qP_Q3vtqN#%;!n^Bl!Gs@vzH7 z!^eFB<>r&gF+s{`&HST@&F+nix!`yLl+FS0xQt5K@!wbvP)FN4XWH3cTVZobjd>e< z6rb5AIeo&1eBo_mh>_&NEo-J^-aAkAS~h65#&zgn9U)ooXG?~Bmv~y@&x&1jx*e*> zT$BA=7yX8ZmY?TdV?N4m=96XMCK`v?jmm%eb=~iMs?-V_9c{_|q zr9O9E;@vnRy=)3&-}vbA$eRIfS4mX7o!Jp}BLe_VCtx+A?t#bCib>{XC|`xj7t_(S zI^L$)^Mu!!-^G%x^+;m_NgA6;cV0BZUP$vYl63mr+7C@;snjQYoWHqzE;pM~Sf}Xt z!Ify)1nr>SSB3?y*nB#RL08~1%g8dW%l@o*8x&%=FO!G6URvUb|! z_^vhzRqy5mW38l9^W=1U|KS;hLZf#_pteeKY?H$F4Rw8< zGdPo#TrZ)E;v#?zc|tQZPkYJ&S3{-ZtPKW%$o!=Aix%{MxvX&fz(sO)^`*uIek6YV z5e`z;nTz;TG{`N{EMSZ#U?w0LTPYv_L`i;YAwrX7S05Z=qnWo>-xAkekVxA79+wyI z+;f!389@M>!*BgWJnZu-?nd-F9)Rxd02bxyVDvhf&)Q z)E_BJ=mR6XrRH{c^V*iT&LoTaZB}fwTXo5)i5@SjNoRfobzU1G*s5-Ra6T)EZQW<3 zUcgN_`7i!YZy3IwhBo(&gN@9=X$NH;P;g(eqIw~w(ok!OnYcw|sH2`s>JF4MK{*R$ zEZF~)bzj4Wm6@x}LDaXVwWf?vfWgC1<}wao%M#rZuOCxn&<$;5(|s=jGHBJR4D4~< zQC9Q%L|d5ka8^x{PBwR`y2^3AWIe`VCb3Uo8GH&aGyxvWC2L8~YA(t~ZT=Ps8e)G? ziW(KDSc?yyvL!lXuY5p!zoY$?q9xvT7}a#nvVGIVh~PEC*Ej}?Rf?n1aRNM1-H)pv z&E9J}JyA|gqzZL}Da6wm$%xHZ!3DQTsdRFV3@WF}^ z{`IGAk&;BFZA2|M(I@YHr}pe#AG6}@L(nW!`KPC! zhuNCQsjqGD`0UYIGRIknLbF{t`7?z8_l*0tUiu1HGs{+c35+I{tw4Yt^WnvQU_j zXJ%}Ip}UGXQ}vKzncP)Wb$ytRrHj6W_KTIh4!?DSD#=68qNTg@A31E9DvvY`WM0dj zSg0V|D(Jl6n5_q`?kmyPYq5N*cDJ5YjDiLrF-z6YJ zIW|thc867_m7_p!0I+~`)>&P(8@bxh@o+mA;1=&p=_2ANc{610TRQbmq&y$|kY@!F zyU$#5>eHa`C}i&dimOkZa)Ry7brfp@Q6i``*e(u^;Gk01Z)!3=bY{-xtK~9%tYvn& zmD&V8j3M}-wox-iDPGd=Tw#^5J-N5;ZF6l@TP%%21}9VHoA{vX{0DGwYZ`YTrK6Wb ztuxts^K^Bw4?L5Ma`J_&|clOI`d8?&{?rITj8an_~Q&D6pW#V6s!H)RqN|- znxp4(7i&{Q>FhvkJu|26b=~!wONA*&@`lK^j~d);&BjhB$)7^;FH- zCK3AWEG$uzFBK3&NI^)AhA#gTh4*-r@Tx_?qlDI>igxtT>^*K^U8*~Byj%P4>0e2l zuZ5Ka?Cns)K1L=Ir8gRaTUHX@yJlneitZ*j_KRZ0I3@>z$o5*;mA7{C{%yY|Y;$tmjKcSHCF>T98jCij-MhviKHv7{zL732nz zuWdtxGapOozh}?Ey~D`6wnQ6Xvp_JScGen!fjI@+lSH+P+7GFFR~via{J?G2*ZjF{ z#;Qw^9GbWE5wxIY`|em9b*bZKNA!1di)&5AR{~E(#pwJTV?}3m24~z;?Vnj_B8tPh z*mR<8rh*EQzx?knqn>!nk-k&AU$vzB+ukP&N z8K)1&dDX7z!;1wH8H0lVMpJE9*d!YigPTpb0W2nca0Wq%-ipKN7OxBbGV@w~6W5s2 zX1t>Ic*1kLID8?XaVpaZH^kjPp*Tb)T4C{1M9P_gDX z6PZXnIBTHClWLC%x;GR{!`oCi2N9~5vXxVuH`y>wW}ouV zj!h)%MW^z=;u9O&p0MtOMkLYWef2ovfW5g*KT}()r#$=IR-<|$!yqNZujO*-ZTH0{>0u z5-@ZG1tD>Y#iB(|G7tsVY7wA;nGYOfHt+Vxcg&GrtFEVS^py*cR6Xj0sI8sOzO(FS ze++ZhZneB<+}W1A^^+3%T?mEaa|{Da4jym%BFtRXs8I-^uJEwVE7@Z?U4kjKfKdSB#!S6ZH=;OhKJ$ z=Oe4v9{zSnLsEE2V7+_R$6&>Uszj77iQmgryarP4G?-FBUnup>P*ft1_64ciE!#dM z--bQvH~V;5QNwIAa1&|>lYj1pho%olB;*MypCzr1aVzTHz3IN!voY~;xHmzq8XF-i zW0-y7JdP)7=}T>{W|Zu(*QZe==KvMT1WWJ4cNZ?Js!LHF%*5W^>!iiFFfiFUNP(x< za(Ya;L1CQbhg3pGdq~yij%Cb^0hs9(VV2^3y3QjzY4{}HMm}C67_t;u@^%-l_k||* zD0h@C_eu=3J|1$z#0BguKVB7L>Rrz2y$|y0Ir8UagAIMVHy3EYRiSW|=me@KT9B_4 zt9^@u24%2ha%JC!)~4Oo+S+r1!4IW;{grB?3g7jQ(J*z(XBum@Nk&<7=B2z00+{#1 z^YSf{kK08v%^|xaWd?fdOH>!W>*W&RvDzh?ETaJ#miHgy8-+PWFyCb)PFJ;4ombq< z(KO4|;m~Y`d!mzO63P_FUXz2imT9<)cX-;HcMk!CAW_&{F^Ve(vh(wYONx^`)?!O1 zRY9Bh$|*XNn)DI|qR28NPV4O)d$9d}ZwF#!I8k5w_e-*2f!w;^UNK{wB^ga`U)A54 z5xdW#yT10j2+B%Vq#?Ox3C%~-3TUrh) zKFqoQ$Yzpiw(PwcK|CcsbX|K=R(CsO%G_}CGO6>7P*a~vNp>_%L*Nql+}Y1>GRm}g z7Gu=O(OtL?B?X79C5a0X-50lZmvB{JObDAy=dqg~MZoG9yLsH;!wzqI+u+k4v=wB^o10AO?U6ac!UyuP8SD=BkE%=Au%{N>ck7wQF|`2}sj}CMy!h|y zegt-P@?d8j7Y$Um;QtW{riuRiL?y%ccS+P zb>D;$F4#r)?eaCRv_*R1g^HMvF2Zh){NPw!`s}tw5hWHv+>fqfBYypo&NObA-1TnP|R;|yLf+A zc&^9q>;>(!7905Q{>kdclwi|AalDqwzcY=CSTxR#;5{@k{uWCy1|93}-TEUzOhAJKwr9cPr&GA(V#wKyRKME0S<{8%@kHSzO*jk& z3XA5;bNjv&UumuaDj0PVXPzn*p~u{0z6K$|GZiThQ<2i(3=mm1ZuIy@Nw~z9S&Hwf zP`J!=(5GMUD5~^gb4rPSJlVrMsWAGi&UK3fm@dcdYkJ&AQVygqvulVWb9uHBuAgJ@ z@*q?b7L8M<(JFLz!}|@WCG=MqC|lE)4Ua23-$^hyjCMGJjdoKS2#+;J$)l1H8}eu0 z7h37#`OFBe41+2$6`k`a+z!3s_^O;&lRXkQG$fah^+;@~D1`$+vws+S{=x!`G-KS26|+Ymja-%VgBb`IC$eHp!)A+IGDQ^P=-AHjO_(9Ao%A$Tc{7vgxDE< z0OXZ4`0PIv>wn>M`T=VQk2wI?K`?OO#XcVZY#=tnC_o4X4FX~iqkj-EgCNTgU=G2I zA;1xWn8ScA1OtWvD+rzr179GhHuB=%Ir8HFFPIU8j~jilA4UOFh;2LuSVC}e3^0Kp z_xMXOrQ?7v#C|^kctfyk0`P(0zxae;iAg{lVkAty1bLVQ3?R1N)Ju|{|B!C_#g3i^ zAn)M8$I}4hl{{E(=Ebg@c`1fq7I1^`Nwa_l1TlUAK@d#-1^7dda1PLcpy%9+esS)l zXz_W#5W<(v1CZzTV44LW;MrbyX@Yq1rM{5Gmwda6FZq;~UUcP*^v*|hu37k|So0P^}BJh}z=K~Q1)C0@t&%VsnGeu% z+7P|d>C3vToW88P*co6C;hWB0`XfDmi5q?XqB}i*@z=U|>96VHr7z-3KpmoUyL{Q7 zsY^iX_5c5d8q9kI(Et1NV0s0RKt4T$UIBzKU6laXpbEhK$G88pA^b9gH>&!-{J(D# icwmNW0OkMrKp}Mf?*;kD|N7Wp17z^py}-XeH~2pQuru}m delta 12794 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 bAn$16!U=%5K&$`Nwh;g+;7+#z{{sFG%ra)c delta 12928 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 From 5a2bcf2af2e0c61d4fa725c8a4a807ef8c5a73b2 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 14 Jan 2025 00:14:53 +0300 Subject: [PATCH 278/296] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bb8ffb..fc6df6b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ # 🔧 ***generator1*** ### 📚 Используемый стек и технологии: -- **Python 3.12+** +- **Python 3.12+**. - **httpx (0.28.1)**: Для выполнения асинхронных HTTP-запросов. - **Jinja2 (3.1.4)**: Для генерации кода на основе шаблонов. - **ruamel.yaml (0.18.6)**: Для работы с YAML файлами. From 8ce0e5217902a727c9934a18d578809c46ab8846 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 14 Jan 2025 00:17:49 +0300 Subject: [PATCH 279/296] update src --- src/generator2/generator_starter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator2/generator_starter.py b/src/generator2/generator_starter.py index 192fe78..3f7e926 100644 --- a/src/generator2/generator_starter.py +++ b/src/generator2/generator_starter.py @@ -1,9 +1,9 @@ import os import subprocess +from .request_methods_generator import generate from .services.constants import GENERATED_CLIENT_FOLDER from .services.logger_setup import setup_logging -from .request_methods_generator import generate from .yaml_processor import process_endpoints @@ -47,7 +47,7 @@ def generate_client(): 'check', f'{dir_path}/models', '--fix', - '--silent' + '--silent', ] ) subprocess.run( From a7c6475a0d7de351fcc7143edaeb648124b10ec8 Mon Sep 17 00:00:00 2001 From: Aleksey Malkov <143039459+shft1@users.noreply.github.com> Date: Tue, 28 Jan 2025 14:23:23 +0300 Subject: [PATCH 280/296] Add openapi yaml file --- openapi.yaml | 2365 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2365 insertions(+) create mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..939326f --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,2365 @@ +openapi: 3.0.3 +info: + title: PachcaAPI - OpenAPI 3.0 + description: Документация к открытому API пачки + version: 3.0.3 +servers: + - url: https://api.pachca.com/api/shared/v1 + +tags: + - name: common methods + description: Everything about common methods + - name: employees + description: Everything about employees + - name: status + description: Everything about + status + - name: tags + description: Everything about + tags + - name: chats and channels + description: Everything about + chats and channels + - name: talk and channel participants + description: Everything about + talk and channel participants + - name: comments + description: Everything about + comments + - name: messages + description: Everything about + messages + - name: reactions to messages + description: Everything about + reactions to messages + - name: reminders + description: Everything about + reminders + +paths: + /custom_properties: + get: + tags: + - common methods + summary: получение списка актульных полей сущности + description: | + Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) + operationId: getCommonMethods + parameters: + - name: entity_type + in: query + description: Тип сущности + required: true + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/CommonMethods' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + /uploads: + post: + tags: + - common methods + summary: получения подписи и ключа для загрузки файла + description: | + Данный метод необходимо использовать для загрузки каждого файла. + + Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. + operationId: getUploads + responses: + '200': + description: Успешный ответ. + content: + application/json: + schema: + $ref: '#/components/schemas/FileResponse' + /direct_url: + post: + tags: + - common methods + summary: (полученный в ответе на запрос /uploads) загрузка файла + description: | + Данный метод не требует авторизации. + + Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. + operationId: getDirectUrl + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/DirectResponse' + responses: + '201': + description: При безошибочном выполнении запроса тело ответа отсутствует. + /users: + get: + tags: + - employees + summary: получение актуального списка всех сотрудников компании + description: | + Метод для получения актуального списка сотрудников вашей компании. + Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) + operationId: getEmployees + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: query + in: query + description: | + Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) + required: false + schema: + type: string + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Employee' + /users/{id}: + get: + tags: + - employees + summary: получение информации о сотруднике + description: | + Метод для получения информации о сотруднике. + Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. + operationId: getEmployee + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Employee' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /profile/status: + get: + tags: + - status + summary: получение информации о своем статусе + description: | + Метод для получения информации о своем статусе. Параметры запроса отсутствуют. + operationId: getStatus + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + put: + tags: + - status + summary: новый статус + description: | + Метод для установки себе нового статуса. + operationId: putStatus + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + status: + $ref: '#/components/schemas/QueryStatus' + responses: + '200': + description: Объект создан + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Status' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: string + value: string + message: message + code: invalid + payload: {} + wrong_emoji: + description: Emoji статуса не может содержать значения отличные от Emoji символа + value: + errors: + - key: string + value: string + message: message + code: wrong_emoji + payload: {} + delete: + tags: + - status + summary: удаление своего статуса + description: | + Метод для удаления своего статуса. Параметры запроса отсутствуют. + operationId: delStatus + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствует + content: {} + /group_tags/{id}: + get: + tags: + - tags + summary: получение информации о теге + description: | + Метод для получения информации о теге. Названия тегов являются уникальными в компании. + + Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют + operationId: getTag + parameters: + - name: id + in: path + description: Уникальный идентификатор тега + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Tag' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /group_tags: + get: + tags: + - tags + summary: получение актуального списка тегов сотрудников + description: | + Метод для получения актуального списка тегов сотрудников. + + Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) + operationId: getTags + parameters: + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Tag' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} + /group_tags/{id}/users: + get: + tags: + - tags + operationId: getTagsEmployees + summary: получение актуального списка сотрудников тега + description: | + Метод для получения актуального списка сотрудников тега. + + Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) + parameters: + - name: id + in: path + description: Уникальный идентификатор сотрудкика + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BaseEmployee' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: exclusion + payload: {} + /chats: + post: + tags: + - chats and channels + operationId: createChat + summary: создание новой беседы или канала + description: | + Метод для создания новой беседы или нового канала. + При создании беседы или канала вы автоматически становитесь участником. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + chat: + $ref: '#/components/schemas/BaseChat' + responses: + '201': + description: Запрос отработал успешно, сущность создана + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + get: + tags: + - chats and channels + operationId: getChats + summary: получение списка бесед и каналов + description: | + Метод для получения списка бесед и каналов по заданным параметрам. + + Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) + parameters: + - name: 'sort[id]' + in: query + required: false + description: | + Составной параметр сортировки сущностей выборки. + Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). + На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). + schema: + type: string + enum: + - desc + - asc + default: desc + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + - name: availability + in: query + required: false + description: | + Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. + Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) + или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). + schema: + type: string + enum: + - is_member + - public + default: is_member + - name: last_message_at_after + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + - name: last_message_at_before + in: query + required: false + description: | + Фильтрация по времени создания последнего сообщения. + Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). + schema: + type: string + format: date-time + responses: + '200': + description: Запрос отработал как положено, без ошибок + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}: + get: + tags: + - chats and channels + operationId: getChat + summary: получение информации о беседе или канале + description: | + Получения информации о беседе или канале. + Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. + parameters: + - name: id + description: Идентификатор беседы или канала + in: path + required: true + schema: + type: integer + responses: + '200': + description: Успешный запрос + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Chat' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /chats/{id}/members: + post: + tags: + - talk and channel participants + summary: добавление пользователей в состав участников + description: | + Метод для добавления пользователей в состав участников беседы или канала. + operationId: postMembersToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) + Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса + content: + application/json: + schema: + $ref: '#/components/schemas/MembersChat' + responses: + '204': + description: Пользователи добавлены + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/group_tags: + post: + tags: + - talk and channel participants + summary: добавление тегов в состав участников беседы или канала + description: | + Метод для добавления тегов в состав участников беседы или канала. + operationId: postTagsToChats + parameters: + - name: id + in: path + description: Идентификатор беседы/канала + required: true + schema: + type: integer + format: int64 + example: 533 + requestBody: + description: | + Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) + Массив идентификаторов тегов, которые станут участниками, передается в теле запроса + content: + application/json: + schema: + $ref: '#/components/schemas/GroupTag' + responses: + '204': + description: Тег(и) добавлен(ы) + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Обязательное поле (не может быть пустым) + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + invalid: + description: Поле не соответствует правилам (пояснения вы получите в поле message) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + '422': + description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + invalid: + description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) + value: + errors: + - key: name + value: name + message: message + code: invalid + payload: {} + /chats/{id}/leave: + delete: + tags: + - talk and channel participants + operationId: leaveChat + summary: выход из беседы или канала + description: |- + Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + responses: + '204': + description: При безошибочном выполнении запроса тело ответа отсутствуе + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + personal_chat: + description: Нельзя покинуть персональный чат + value: + errors: + - key: string + value: string + message: message + code: personal_chat + payload: {} + /messages/{id}/thread: + post: + tags: + - comments + summary: создание нового треда + description: | + Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. + operationId: createThread + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения, к которому создается тред. + schema: + type: integer + responses: + '201': + description: Тред успешно создан или возвращены данные существующего треда. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Thread' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages: + post: + tags: + - messages + summary: создание нового сообщения + description: | + Метод для отправки сообщения в беседу или канал, + личного сообщения пользователю или комментария в тред. + + При использовании entity_type: "discussion" (или просто без указания entity_type) + допускается отправка любого chat_id в поле entity_id. + То есть, сообщение можно отправить зная только идентификатор чата. + При этом, вы имеете возможность отправить сообщение в тред по его идентификатору + или личное сообщение по идентификатору пользователя. + + Для отправки личного сообщения пользователю создавать чат не требуется. + Достаточно указать entity_type: "user" и идентификатор пользователя. + Чат будет создан автоматически, если между вами ещё не было переписки. + Между двумя пользователями может быть только один личный чат. + operationId: createMessage + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/CreateMessage' + responses: + '201': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - messages + summary: получение списка сообщений чата + description: | + Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. + + Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, + треда или диалога, и указать его в URL запроса. Сообщения будут возвращены + в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). + Для получения более ранних сообщений чата доступны параметры per и page. + Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) + operationId: getListMessage + parameters: + - name: chat_id + in: query + description: Идентификатор чата (беседа, канал, диалог или чат треда) + required: true + schema: + title: chat_id + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) + required: false + schema: + type: integer + default: 25 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Successful + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Message' + example: + data: + - id: 1194277 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Это сообщение тоже попадёт в экспорт + user_id: 12 + created_at: 2023-09-18T13:43:32.000Z + files: [] + buttons: [] + thread: + id: 2633 + chat_id: 44997 + forwarding: null + parent_message_id: null + - id: 1194276 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** добавил **Export bot** в беседу" + user_id: 12 + created_at: 2023-09-18T13:43:27.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + - id: 1194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: "**Andrew** создал беседу" + user_id: 12 + created_at: 2023-09-18T13:43:19.000Z + files: [] + buttons: [] + thread: null + forwarding: null + parent_message_id: null + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages/{id}: + get: + tags: + - messages + summary: получение информации о сообщении + description: | + Метод для получения информации о сообщении. + + Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + operationId: getMessage + parameters: + - name: id + in: path + required: true + schema: + title: id + type: integer + responses: + '200': + description: Successfull + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + example: + data: + id: 194275 + entity_type: discussion + entity_id: 198 + chat_id: 198 + content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) + user_id: 12 + created_at: 2020-06-08T09:32:57.000Z + files: + - id: 3560 + key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png + name: congrat.png + file_type: file + url: | + https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- + 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- + age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC + -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ + request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= + host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 + buttons: [] + thread: + id: 29873 + chat_id: 1949863 + forwarding: null + parent_message_id: 194274 + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + put: + tags: + - messages + operationId: editMessage + summary: редактирование сообщения по указанному идентификатору + description: Метод для редактирования сообщения или комментария. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор беседы или канала. + schema: + type: integer + requestBody: + description: Массив идентификаторов тегов, которые станут участниками + content: + application/json: + schema: + type: object + properties: + message: + $ref: '#/components/schemas/EditMessages' + responses: + '200': + description: Успешно отредактировано + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Message' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /messages/{id}/reactions: + post: + tags: + - reactions to messages + operationId: postMessageReactions + summary: добавление реакции + description: > + Метод для добавления реакции на сообщение. + **Лимиты реакций:** + - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. + - Сообщение может иметь не более 30 уникальных реакций. + - Сообщение может иметь не более 1000 реакций. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CodeReaction' + responses: + "201": + description: Успешное выполнение запроса, тело ответа отсутствует. + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + user_limit: + description: Превышен лимит уникальных реакций пользователя + value: + errors: + - key: string + value: string + message: Вы можете добавить не более 20 уникальных реакций. + code: user_limit + payload: {} + unique_limit: + description: Превышен лимит уникальных реакций на сообщение + value: + errors: + - key: string + value: string + message: Сообщение может содержать не более 30 уникальных реакций. + code: unique_limit + payload: {} + general_limit: + description: Превышен общий лимит реакций на сообщение + value: + errors: + - key: string + value: string + message: Сообщение может содержать не более 1000 реакций. + code: general_limit + payload: {} + delete: + tags: + - reactions to messages + operationId: deleteMessageReactions + summary: удаление реакции + description: > + Метод для удаления реакции на сообщение. + Удалить можно только те реакции, которые были поставлены авторизованным пользователем. + parameters: + - name: id + in: path + required: true + description: Уникальный идентификатор сообщения. + schema: + type: integer + - name: code + in: query + description: Emoji в строковом формате для добавления реакции. + schema: + type: string + example: "👍" + responses: + "204": + description: При безошибочном выполнении запроса тело ответа отсутствует + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: name + value: '' + message: message + code: blank + payload: {} + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + get: + tags: + - reactions to messages + operationId: getMessageReactions + summary: получение актуального списка реакций + description: | + Метод для получения актуального списка реакций на сообщение. + + Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса + parameters: + - name: id + in: path + description: Уникальный идентификатор сообщения + required: true + schema: + type: integer + - name: per + in: query + description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) + required: false + schema: + type: integer + default: 50 + maximum: 50 + - name: page + in: query + description: Страница выборки (по умолчанию 1) + required: false + schema: + type: integer + default: 1 + responses: + '200': + description: Список реакций успешно получен. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Reaction' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + exclusion: + description: Поле имеет недопустимое значение + value: + errors: + - key: name + value: 1234 + message: message + code: exclusion + payload: {} + not_found: + description: Не удалось найти + value: + errors: + - key: string + value: string + message: message + code: not_found + payload: {} + /tasks: + post: + tags: + - reminders + operationId: createTask + summary: создание нового напоминания + description: | + Метод для создания нового напоминания. + + При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. + При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. + Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. + У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + task: + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания (call, meeting, reminder, event, email) + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + responses: + '201': + description: Напоминание успешно создано + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Task' + '400': + description: Пояснения ошибки + content: + application/json: + schema: + $ref: '#/components/schemas/Errors' + examples: + blank: + description: Поле не может быть пустым + value: + errors: + - key: string + value: string + message: message + code: blank + payload: {} + too_long: + description: Слишком длинное значение (пояснения вы получите в поле message) + value: + errors: + - key: name + value: long_name + message: message + code: too_long + payload: {} + inclusion: + description: Поле имеет непредусмотренное значение + value: + errors: + - key: string + value: string + message: message + code: inclusion + payload: {} + invalid: + description: Поле имеет неверное значение (например, указаны недопустимые ответственные) + value: + errors: + - key: name + value: 1234 + message: message + code: invalid + payload: {} +components: + schemas: + MembersChat: + title: Members Chat + required: + - member_ids + type: object + properties: + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + minItems: 1 + items: + type: integer + format: int64 + example: [186, 187] + silent: + type: boolean + description: Не создавать в чате системное сообщение о добавлении участника + GroupTag: + title: Group Tag + required: + - group_tag_ids + type: object + properties: + group_tag_ids: + type: array + minItems: 1 + items: + type: integer + format: int64 + example: [86, 18] + description: Массив идентификаторов тегов, которые станут участниками + CodeReaction: + title: Code Reaction + type: object + properties: + code: + type: string + example: "👍" + description: Emoji в строковом формате для добавления реакции. + required: + - code + BaseEmployee: + title: Base Employee + type: object + properties: + id: + type: integer + example: 1 + description: Идентификатор пользователя + first_name: + type: string + description: Имя + last_name: + type: string + description: Фамилия + nickname: + type: string + description: Имя пользователя + email: + type: string + description: Электронная почта + phone_number: + type: string + description: Телефон + department: + type: string + description: Департамент + role: + type: string + enum: + - admin + - user + - multi_guest + description: | + Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) + suspended: + type: boolean + description: | + Деактивация пользователя. При значении true пользователь является деактивированным. + invite_status: + type: string + enum: + - confirmed + - sent + description: | + Статус приглашения: confirmed (принято), sent (отправлено) + list_tags: + type: array + items: + type: string + description: Массив тегов, привязанных к сотруднику + custom_properties: + type: array + description: Дополнительные поля сотрудника + items: + type: object + properties: + id: + type: integer + description: Идентификатор поля + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + value: + type: string + description: Значение + bot: + type: boolean + description: | + Тип: пользователь (false) или бот (true) + description: Базовый класс сотрудника. + Employee: + allOf: + - $ref: '#/components/schemas/BaseEmployee' + - type: object + properties: + user_status: + $ref: '#/components/schemas/Status' + title: + type: string + description: Должность + created_at: + type: string + format: date-time + description: | + Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + time_zone: + type: string + description: Часовой пояс пользователя + image_url: + type: string + nullable: true + description: Ссылка на скачивание аватарки + description: Расширенный класс сотрудника. + BaseResponse: + title: Base Response + type: object + properties: + Content-Disposition: + type: string + description: Используемый заголовок + default: attachment + acl: + type: string + description: Уровень безопасности + default: private + policy: + type: string + description: Уникальный policy для загрузки файла + x-amz-credential: + type: string + description: x-amz-credential для загрузки файла + x-amz-algorithm: + type: string + description: Используемый алгоритм + default: AWS4-HMAC-SHA256 + x-amz-date: + type: string + description: Уникальный x-amz-date для загрузки файла + x-amz-signature: + type: string + description: Уникальная подпись для загрузки файла + key: + type: string + description: Уникальный ключ для загрузки файла + FileResponse: + title: File Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + direct_url: + type: string + description: Адрес для загрузки файла + DirectResponse: + title: Direct Response + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + file: + type: string + description: Адрес для загрузки файла + Status: + type: object + nullable: true + description: Статус. Возвращается как null, если статус не установлен. + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + nullable: true + description: | + Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. + QueryStatus: + type: object + properties: + status: + type: object + description: Собранный объект параметров нового статуса + required: + - emoji + - title + properties: + emoji: + type: string + description: Emoji символ статуса + title: + type: string + description: Текст статуса + expires_at: + type: string + format: date-time + description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + nullable: true + CommonMethods: + title: Common Methods + type: object + description: получение списка актульных полей сущности. + properties: + id: + type: integer + example: 1 + description: Название поля + name: + type: string + example: Дата рождения + description: Идентификатор поля + data_type: + type: string + enum: + - string + - number + - date + - link + example: number + description: тип поля + Errors: + type: object + properties: + errors: + type: array + items: + key: + title: key + type: string + description: Ключ параметра, в котором произошла ошибка + value: + title: value + type: string + description: Значение ключа, которое вызвало ошибку + message: + title: message + type: string + description: Ошибка текстом, который вы можете вывести пользователю + code: + title: code + type: string + description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) + payload: + title: payload + type: object + description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) + Buttons: + title: Message Buttons + type: array + maxItems: 100 + items: + title: Row Buttons + type: array + maxItems: 8 + items: + type: object + title: Button + required: + - text + minProperties: 2 + properties: + text: + title: Text + type: string + maxLength: 255 + url: + title: Url + type: string + data: + title: Data + type: string + maxLength: 255 + BaseThread: + title: Base Thread + type: object + properties: + id: + type: integer + description: Идентификатор поля + chat_id: + type: integer + description: Идентификатор поля чата + Thread: + allOf: + - $ref: '#/components/schemas/BaseThread' + - type: object + properties: + message_id: + type: integer + description: Идентификатор сообщения, к которому был создан тред. + message_chat_id: + type: integer + description: Идентификатор чата сообщения. + updated_at: + type: string + format: date-time + description: | + Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + BaseFiles: + title: Base Files + type: object + required: + - key + - name + - file_type + properties: + key: + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + type: string + enum: + - file + - image + CreateEditFiles: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Create&Edit Files + required: + - size + properties: + size: + type: integer + description: Размер файла в байтах, отображаемый пользователю + Files: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseFiles' + - type: object + title: Files + properties: + id: + type: integer + description: Идентификатор поля + url: + type: string + description: Прямая временная ссылка на скачивание файла + BeforeBaseMessages: + title: Before Base Messages + type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + content: + type: string + description: Текст сообщения + default: Текст сообщения + buttons: + allOf: + - $ref: '#/components/schemas/Buttons' + title: buttons + EditMessages: + title: Edit Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. + required: + - content + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + BaseMessages: + title: Base Messages + allOf: + - $ref: '#/components/schemas/BeforeBaseMessages' + - type: object + required: + - entity_id + properties: + entity_type: + title: Entity Type + type: string + enum: + - discussion + - user + - thread + default: discussion + entity_id: + title: Entity Id + type: integer + parent_message_id: + title: Parent Massage Id + type: integer + nullable: true + default: null + description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. + CreateMessage: + title: Create Messages + allOf: + - $ref: '#/components/schemas/BaseMessages' + - type: object + properties: + files: + allOf: + - $ref: '#/components/schemas/CreateEditFiles' + title: files + skip_invite_mentions: + title: Skip Invite Mentions + type: boolean + default: false + link_preview: + title: Link Preview + type: boolean + default: false + Message: + type: object + properties: + entity_type: + title: Entity Type + type: string + enum: + - 'discussion' + - 'user' + - 'thread' + default: 'discussion' + entity_id: + title: Entity Id + type: integer + content: + title: Content + type: string + id: + title: Id + type: integer + chat_id: + title: Chat Id + type: integer + user_id: + title: User Id + type: integer + created_at: + title: Created At + type: string + format: date-time + files: + title: Files + type: array + items: + type: object + properties: + id: + title: Id + type: integer + key: + title: Key + type: string + description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) + name: + title: Name + type: string + description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) + file_type: + title: File Type + type: string + enum: + - 'file' + - 'image' + url: + title: Url + type: string + description: Размер файла в байтах, отображаемый пользователю + Reaction: + type: object + properties: + user_id: + type: integer + description: | + Идентификатор пользователя, оставившего реакцию. + created_at: + type: string + format: date-time + description: | + Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. + code: + type: string + description: | + Emoji символ реакции. + BaseChat: + title: Base Chat + type: object + description: Собранный объект параметров создаваемой беседы или канала + required: + - name + properties: + name: + type: string + description: Название + example: 🤿 aqua + member_ids: + type: array + description: Массив идентификаторов пользователей, которые станут участниками + items: + type: integer + example: + - 186 + - 187 + group_tag_ids: + type: array + description: Массив идентификаторов тегов, участников + items: + type: integer + example: [] + channel: + type: boolean + description: 'Тип: беседа (по умолчанию, false) или канал (true)' + example: true + public: + type: boolean + description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' + example: false + Chat: + allOf: + - type: object + properties: + id: + type: integer + description: Идентификатор беседы или канала + example: 334 + owner_id: + type: integer + description: Идентификатор пользователя, создавшего беседу или канал + example: 185 + created_at: + type: string + format: date-time + description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:56:53.000Z' + last_message_at: + type: string + format: date-time + description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ + example: '2021-08-28T15:58:13.000Z' + meet_room_url: + type: string + description: Ссылка на Видеочат + example: 'https://meet.pachca.com/aqua-94bb21b5' + - $ref: '#/components/schemas/BaseChat' + Tag: + type: object + description: Для получения тега вам необходимо знать его id и указать его в URL запроса. + properties: + id: + type: integer + description: Идентификатор тега + name: + type: string + description: Название тега + users_count: + description: Количество сотрудников, которые имеют этот тег + type: integer + BaseCustomProperties: + title: Base Custom Properties + description: Задаваемые дополнительные поля + type: object + properties: + id: + type: integer + description: Идентификатор поля + value: + type: string + description: Значение поля + CustomProperties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + - type: object + title: Custom Properties + properties: + name: + type: string + description: Название поля + data_type: + type: string + enum: + - string + - number + - date + - link + description: Тип поля (string, number, date или link) + BaseTask: + title: Base Task + type: object + required: + - kind + - content + - due_at + properties: + kind: + type: string + description: Тип напоминания + enum: + - call + - meeting + - reminder + - event + - email + content: + type: string + description: Описание напоминания + due_at: + type: string + format: date-time + description: Срок выполнения напоминания (ISO-8601) + priority: + type: integer + description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) + enum: + - 1 + - 2 + - 3 + performer_ids: + type: array + items: + type: integer + description: Массив идентификаторов пользователей + custom_properties: + type: array + items: + allOf: + - $ref: '#/components/schemas/BaseCustomProperties' + Task: + allOf: + - $ref: '#/components/schemas/BaseTask' + - type: object + properties: + id: + type: integer + description: Идентификатор созданного напоминания + user_id: + type: integer + description: Идентификатор пользователя-создателя + status: + type: string + description: Статус напоминания + created_at: + type: string + format: date-time + description: Дата и время создания + custom_properties: + allOf: + - $ref: '#/components/schemas/CustomProperties' + securitySchemes: + bearerAuth: + type: http + scheme: bearer +security: + - bearerAuth: [] From fa05a66036865b655e11c0aae844984071854de6 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 29 Jan 2025 13:29:07 +0300 Subject: [PATCH 281/296] formatter generator1 --- src/generator1/client_servis.py | 88 +++++++++++++---- src/generator1/generator.py | 75 +++++--------- src/generator1/logger_setup.py | 5 +- src/generator1/pachca.py | 68 +++++++------ src/generator1/script.py | 167 +++++++++++++++++++------------- 5 files changed, 232 insertions(+), 171 deletions(-) diff --git a/src/generator1/client_servis.py b/src/generator1/client_servis.py index cc2a26d..d465483 100644 --- a/src/generator1/client_servis.py +++ b/src/generator1/client_servis.py @@ -31,21 +31,55 @@ class AuthenticatedClient: """ raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(default="https://api.pachca.com/api/shared/v1", kw_only=True, alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _base_url: str = field( + default='https://api.pachca.com/api/shared/v1', + kw_only=True, + alias='base_url', + ) + _cookies: dict[str, str] = field( + factory=dict, + kw_only=True, + alias='cookies', + ) + _headers: dict[str, str] = field( + factory=dict, + kw_only=True, + alias='headers', + ) + _timeout: Optional[httpx.Timeout] = field( + default=None, + kw_only=True, + alias='timeout', + ) + _verify_ssl: Union[str, bool, ssl.SSLContext] = field( + default=True, + kw_only=True, + alias='verify_ssl', + ) + _follow_redirects: bool = field( + default=False, + kw_only=True, + alias='follow_redirects', + ) + _httpx_args: dict[str, Any] = field( + factory=dict, + kw_only=True, + alias='httpx_args', + ) _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field( + default=None, + init=False, + ) token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" + prefix: str = 'Bearer' + auth_header_name: str = 'Authorization' - async def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + async def with_headers( + self, + headers: dict[str, str], + ) -> 'AuthenticatedClient': """Get a new client matching this one with additional headers""" if self._client is not None: self._client.headers.update(headers) @@ -53,7 +87,10 @@ async def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": self._async_client.headers.update(headers) return evolve(self, headers={**self._headers, **headers}) - async def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + async def with_cookies( + self, + cookies: dict[str, str], + ) -> 'AuthenticatedClient': """Get a new client matching this one with additional cookies""" if self._client is not None: self._client.cookies.update(cookies) @@ -61,7 +98,10 @@ async def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": self._async_client.cookies.update(cookies) return evolve(self, cookies={**self._cookies, **cookies}) - async def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + async def with_timeout( + self, + timeout: httpx.Timeout, + ) -> 'AuthenticatedClient': """Get a new client matching this one with a new timeout (in seconds)""" if self._client is not None: self._client.timeout = timeout @@ -69,7 +109,10 @@ async def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": self._async_client.timeout = timeout return evolve(self, timeout=timeout) - async def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + async def set_httpx_client( + self, + client: httpx.Client, + ) -> 'AuthenticatedClient': """Manually set the underlying httpx.Client **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. @@ -80,7 +123,9 @@ async def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": async def get_httpx_client(self) -> httpx.Client: """Get the underlying httpx.Client, constructing a new one if not previously set""" if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._headers[self.auth_header_name] = ( + f'{self.prefix} {self.token}' if self.prefix else self.token + ) self._client = httpx.Client( base_url=self._base_url, cookies=self._cookies, @@ -92,7 +137,7 @@ async def get_httpx_client(self) -> httpx.Client: ) return self._client - async def __enter__(self) -> "AuthenticatedClient": + async def __enter__(self) -> 'AuthenticatedClient': """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" await self.get_httpx_client().__enter__() return self @@ -101,7 +146,10 @@ async def __exit__(self, *args: Any, **kwargs: Any) -> None: """Exit a context manager for internal httpx.Client (see httpx docs)""" await self.get_httpx_client().__exit__(*args, **kwargs) - async def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + async def set_async_httpx_client( + self, + async_client: httpx.AsyncClient, + ) -> 'AuthenticatedClient': """Manually the underlying httpx.AsyncClient **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. @@ -112,7 +160,9 @@ async def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Auth async def get_async_httpx_client(self) -> httpx.AsyncClient: """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._headers[self.auth_header_name] = ( + f'{self.prefix} {self.token}' if self.prefix else self.token + ) self._async_client = httpx.AsyncClient( base_url=self._base_url, cookies=self._cookies, @@ -124,7 +174,7 @@ async def get_async_httpx_client(self) -> httpx.AsyncClient: ) return self._async_client - async def __aenter__(self) -> "AuthenticatedClient": + async def __aenter__(self) -> 'AuthenticatedClient': """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" await self.get_async_httpx_client().__aenter__() return self diff --git a/src/generator1/generator.py b/src/generator1/generator.py index 9164b86..e8e8478 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -3,33 +3,40 @@ MIN_ARGS = 2 COMMAND_INDEX = 1 -GENERATE_COMMAND = "generate" -INSTALL_TEST_COMMAND = "test" +GENERATE_COMMAND = 'generate' +INSTALL_TEST_COMMAND = 'test' def run_command(command): """Функция для выполнения команды в терминале.""" try: subprocess.run(command, check=True, shell=True, text=True) - print(f"Команда выполнена: {command}") + print(f'Команда выполнена: {command}') except subprocess.CalledProcessError as e: - print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") + print( + f'Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}' + ) + def generate_client(): """Генерация клиента и запуск скрипта-генератора.""" - print("Генерация клиента...") - run_command("openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite") - run_command("python script.py") + print('Генерация клиента...') + run_command( + 'openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite' + ) + run_command('python script.py') + def install_and_run_tests(): """Установка пакета и запуск тест-запросов.""" - print("Установка пакета и запуск тест-запросов...") - run_command("pip install ./pachca-api-open-api-3-0-client") - run_command("python pachca.py") + print('Установка пакета и запуск тест-запросов...') + run_command('pip install ./pachca-api-open-api-3-0-client') + run_command('python pachca.py') + -if __name__ == "__main__": +if __name__ == '__main__': if len(sys.argv) < MIN_ARGS: - print("Пример команды: python generator.py [generate|test]") + print('Пример команды: python generator.py [generate|test]') sys.exit(COMMAND_INDEX) command = sys.argv[COMMAND_INDEX] @@ -40,45 +47,7 @@ def install_and_run_tests(): if command in commands: commands[command]() else: - print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") + print( + "Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов." + ) sys.exit(COMMAND_INDEX) - - - -# import subprocess -# import sys - -# def run_command(command): -# """Функция для выполнения команды в терминале.""" -# try: -# subprocess.run(command, check=True, shell=True, text=True) -# print(f"Команда выполнена: {command}") -# except subprocess.CalledProcessError as e: -# print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") - -# def generate_client(): -# """Генерация клиента и запуск скрипта-генератора.""" -# print("Генерация клиента...") -# run_command("openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite") -# run_command("python script.py") - -# def install_and_run_tests(): -# """Установка пакета и запуск тест-запросов.""" -# print("Установка пакета и запуск тест-запросов...") -# run_command("pip install ./pachca-api-open-api-3-0-client") -# run_command("python pachca.py") - -# if __name__ == "__main__": -# if len(sys.argv) != 2: -# print("Пример команды: python generator.py [generate|test]") -# sys.exit(1) - -# option = sys.argv[1] - -# if option == "generate": -# generate_client() -# elif option == "test": -# install_and_run_tests() -# else: -# print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") -# sys.exit(1) diff --git a/src/generator1/logger_setup.py b/src/generator1/logger_setup.py index fa06bd7..123e21d 100644 --- a/src/generator1/logger_setup.py +++ b/src/generator1/logger_setup.py @@ -3,13 +3,14 @@ def setup_logging( logger_name: str, - file_name: str = 'client_generator.log' + file_name: str = 'client_generator.log', ) -> logging.Logger: logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) file_handler = logging.FileHandler(file_name, encoding='utf-8') formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s') + '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + ) file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index baac452..e9bf144 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -14,7 +14,6 @@ QueryStatusStatus, ) from pachca_api_open_api_3_0_client.models.base_chat import BaseChat -from pachca_api_open_api_3_0_client.models.chat import Chat from pachca_api_open_api_3_0_client.models.code_reaction import ( CodeReaction, ) @@ -30,29 +29,25 @@ from pachca_api_open_api_3_0_client.models.create_task_body import ( CreateTaskBody, ) -from pachca_api_open_api_3_0_client.models.put_status_body import ( - PutStatusBody, -) load_dotenv() pachca = Pachca(os.getenv('TOKEN')) logger = setup_logging( 'test_requests_logging', - 'pachca_testresults.log' + 'pachca_testresults.log', ) async def main() -> None: - """ Функция теста эндпоинтов """ + """Функция теста эндпоинтов""" # подготовка запроса на создание беседы --> query_chat = BaseChat(name='test500_2') chat_body = CreateChatBody(chat=query_chat) # <-- # запрос на создание беседы - chat_create = asyncio.create_task( - pachca.createChat(body=chat_body)) + chat_create = asyncio.create_task(pachca.createChat(body=chat_body)) chat_response = await chat_create # запрос на получение списка бесед и каналов @@ -60,28 +55,33 @@ async def main() -> None: # запрос на получение информации о беседе getChat = await asyncio.create_task( - pachca.getChat(id=chat_response.data.id) + pachca.getChat(id=chat_response.data.id), ) # подготовка запроса на создание сообщения в созданную беседу --> create_message = CreateMessages( - entity_id=chat_response.data.id, content='Super puper') + entity_id=chat_response.data.id, + content='Super puper', + ) message_body = CreateMessageBody(message=create_message) # <-- # запрос на создание сообщения в созданную беседу message_create = asyncio.create_task( - pachca.createMessage(body=message_body)) + pachca.createMessage(body=message_body), + ) message_response = await message_create # создание треда к созданному сообщению thread_create = asyncio.create_task( - pachca.createThread(id=message_response.data.id) + pachca.createThread(id=message_response.data.id), ) # запрос на получение списка сообщений getListMessage = await asyncio.create_task( - pachca.getListMessage(chat_id=chat_response.data.id)) + pachca.getListMessage(chat_id=chat_response.data.id), + ) # запрос на получение сообщения getMessage = await asyncio.create_task( - pachca.getMessage(id=message_response.data.id)) + pachca.getMessage(id=message_response.data.id), + ) # подготовка запроса на редактирование сообщения --> edit_meassage = EditMessages(content='NOT SUPER PUPER') @@ -90,27 +90,31 @@ async def main() -> None: # запрос на редактирование сообщения editMessage = await asyncio.create_task( pachca.editMessage( - id=message_response.data.id, body=edit_message_body) - ) + id=message_response.data.id, + body=edit_message_body, + ), + ) # подготовка запроса на добавление реакции к сообщению --> post_reactions = CodeReaction(code='😭') # <-- # запрос на добавление реакции к сообщению postMessageReactions = await pachca.postMessageReactions( - id=message_response.data.id, body=post_reactions + id=message_response.data.id, + body=post_reactions, ) # подготовка запроса на получение списка реакций к сообщению --> # <-- # запрос на получение списка реакций getMessageReactions = await pachca.getMessageReactions( - id=message_response.data.id + id=message_response.data.id, ) # запрос на удаление реакции deleteMessageReactions = await pachca.deleteMessageReactions( - id=message_response.data.id, code='😭' + id=message_response.data.id, + code='😭', ) # подготовка запроса на создание напоминания --> @@ -123,7 +127,7 @@ async def main() -> None: # <-- # запрос на создание напоминания createtaskbody = await asyncio.create_task( - pachca.createTask(body=body_task) + pachca.createTask(body=body_task), ) # запрос на получения списка пользователей @@ -131,22 +135,22 @@ async def main() -> None: # запрос на получение информации о пользователе getEmployee = await asyncio.create_task( - pachca.getEmployee(id=users_response.data[0].id) + pachca.getEmployee(id=users_response.data[0].id), ) # подготовка запроса на добавление участника --> chats_body = MembersChat(member_ids=[users_response.data[0].id]) # <-- # запрос на добавление участника в беседу - postMembersToChats = await asyncio.create_task(pachca.postMembersToChats( - id=chat_response.data.id, body=chats_body) + postMembersToChats = await asyncio.create_task( + pachca.postMembersToChats(id=chat_response.data.id, body=chats_body), ) # подготовка запроса на добавление статуса --> query_status = QueryStatusStatus( emoji='😭', title='Я не плачу это просто слезы', - expires_at=None + expires_at=None, ) # <-- # запрос на добавление статуса @@ -170,7 +174,7 @@ async def main() -> None: # запрос получение информации о теге участников getTagsEmployees = await asyncio.create_task( - pachca.getTagsEmployees(id=tag_id) + pachca.getTagsEmployees(id=tag_id), ) # подготовка запроса на добавление участника --> @@ -178,19 +182,20 @@ async def main() -> None: # <-- # запрос на добавление тегов в состав участников беседы или канала postTagsToChats = await asyncio.create_task( - pachca.postTagsToChats(id=chat_response.data.id, body=tags_body) + pachca.postTagsToChats(id=chat_response.data.id, body=tags_body), ) # запрос на получение списка актуальных полей сущности getCommonMethods = await asyncio.create_task( - pachca.getCommonMethods(entity_type='User')) + pachca.getCommonMethods(entity_type='User'), + ) # запрос получения подписи и ключа для загрузки файла getUploads = await asyncio.create_task(pachca.getUploads()) # запрос исключение участника из беседы leaveChat = await asyncio.create_task( - pachca.leaveChat(id=chat_response.data.id) + pachca.leaveChat(id=chat_response.data.id), ) logger.debug(await pachca.getUploads()) @@ -223,13 +228,12 @@ async def main() -> None: getUploads, leaveChat, ): - result = task logger.debug( - f"{task}: data={result} \n" - "***", + f'{task}: data={result} \n***', ) - logger.debug('Tests ended '+'*'*100) + logger.debug('Tests ended ' + '*' * 100) + if __name__ == '__main__': asyncio.run(main()) diff --git a/src/generator1/script.py b/src/generator1/script.py index f6c14a6..5363f20 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -8,7 +8,7 @@ def extract_functions_and_imports_from_file(file_path) -> None: - with open(file_path, "r", encoding="utf-8") as file: + with open(file_path, 'r', encoding='utf-8') as file: tree = ast.parse(file.read()) functions = [] @@ -21,27 +21,28 @@ def extract_functions_and_imports_from_file(file_path) -> None: ): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): - module = node.module if node.module else "." + module = node.module if node.module else '.' for alias in node.names: - if module == "typing": - imports.append(f"from typing import {alias.name}") - elif module.startswith("models"): - imports.append(f"from .models import {alias.name}") - elif module == "types": - imports.append(f"from .types import {alias.name}") - elif module == "client_serv": - imports.append(f"from .client_serv import {alias.name}") + if module == 'typing': + imports.append(f'from typing import {alias.name}') + elif module.startswith('models'): + imports.append(f'from .models import {alias.name}') + elif module == 'types': + imports.append(f'from .types import {alias.name}') + elif module == 'client_serv': + imports.append(f'from .client_serv import {alias.name}') else: - imports.append(f"from {module} import {alias.name}") + imports.append(f'from {module} import {alias.name}') return functions, imports + def get_all_api_functions_and_imports(api_dir): all_functions = [] all_imports = [] for root, _, files in os.walk(api_dir): for file in files: - if file.endswith(".py"): + if file.endswith('.py'): file_path = os.path.join(root, file) functions, imports = extract_functions_and_imports_from_file( file_path, @@ -52,13 +53,13 @@ def get_all_api_functions_and_imports(api_dir): def get_base_url_from_yaml(openapi_yaml): - with open(openapi_yaml, "r", encoding="utf-8") as file: + with open(openapi_yaml, 'r', encoding='utf-8') as file: data = yaml.safe_load(file) - return data["servers"][0]["url"] + return data['servers'][0]['url'] -api_dir = "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api" -openapi_yaml = "openapi.yaml" +api_dir = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api' +openapi_yaml = 'openapi.yaml' endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) @@ -66,98 +67,134 @@ def get_base_url_from_yaml(openapi_yaml): loader=FileSystemLoader('templates'), ) -client_template = env.get_template("client.py.jinja") +client_template = env.get_template('client.py.jinja') client_path = ( - "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py" + './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' ) -with open(client_path, mode='w', encoding="utf-8") as file: +with open(client_path, mode='w', encoding='utf-8') as file: unique_imports = list(set(imports)) models_imports = sorted( - [model for model in unique_imports if model.startswith( - 'from .models', - )], + [ + model + for model in unique_imports + if model.startswith( + 'from .models', + ) + ], ) typing_imports = sorted( - [model for model in unique_imports if model.startswith( - 'from typing import', - )], + [ + model + for model in unique_imports + if model.startswith( + 'from typing import', + ) + ], ) types_imports = sorted( - [model for model in unique_imports if model.startswith( - 'from .types import', - )], + [ + model + for model in unique_imports + if model.startswith( + 'from .types import', + ) + ], ) other_imports = sorted( list( - set(unique_imports) - set(typing_imports) - - set(types_imports) - set(models_imports), - )) + set(unique_imports) + - set(typing_imports) + - set(types_imports) + - set(models_imports), + ), + ) if models_imports: - models_imports_str = "from .models import (\n " + ",\n ".join( - [model.split('from .models import ')[-1] for model in models_imports] - ) + "\n)" - file.write(models_imports_str + "\n\n") + models_imports_str = ( + 'from .models import (\n ' + + ',\n '.join( + [ + model.split('from .models import ')[-1] + for model in models_imports + ], + ) + + '\n)' + ) + file.write(models_imports_str + '\n\n') if typing_imports: - typing_imports_str = "from typing import (\n " + ",\n ".join( - [model.split('from typing import ')[-1] for model in typing_imports] - ) + "\n)" - file.write(typing_imports_str + "\n\n") + typing_imports_str = ( + 'from typing import (\n ' + + ',\n '.join( + [ + model.split('from typing import ')[-1] + for model in typing_imports + ], + ) + + '\n)' + ) + file.write(typing_imports_str + '\n\n') if types_imports: - types_imports_str = "from .types import (\n " + ",\n ".join( - [model.split('from .types import ')[-1] for model in types_imports] - ) + "\n)" - file.write(types_imports_str + "\n\n") + types_imports_str = ( + 'from .types import (\n ' + + ',\n '.join( + [ + model.split('from .types import ')[-1] + for model in types_imports + ], + ) + + '\n)' + ) + file.write(types_imports_str + '\n\n') if other_imports: - file.write("\n".join(other_imports) + "\n\n") + file.write('\n'.join(other_imports) + '\n\n') file.write(client_template.render(endpoints=endpoints, base_url=base_url)) cli_servis_path = ( - "./pachca-api-open-api-3-0-client/" - "pachca_api_open_api_3_0_client/" - "client_serv.py" + './pachca-api-open-api-3-0-client/' + 'pachca_api_open_api_3_0_client/' + 'client_serv.py' ) logger_setup_path = ( - "./pachca-api-open-api-3-0-client/" - "pachca_api_open_api_3_0_client/" - "logger_setup.py" + './pachca-api-open-api-3-0-client/' + 'pachca_api_open_api_3_0_client/' + 'logger_setup.py' ) source_file_serv = os.path.join( os.path.dirname(__file__), - "..", - "generator1", - "client_servis.py", + '..', + 'generator1', + 'client_servis.py', ) shutil.copy(source_file_serv, cli_servis_path) source_file_log = os.path.join( os.path.dirname(__file__), - "..", - "generator1", - "logger_setup.py", + '..', + 'generator1', + 'logger_setup.py', ) shutil.copy(source_file_log, logger_setup_path) try: subprocess.run( [ - "black", - "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/" - "client.py", - "--line-length", - "79", + 'black', + './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/' + 'client.py', + '--line-length', + '79', ], check=True, ) subprocess.run( [ - "isort", - "./pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/" - "client.py", + 'isort', + './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/' + 'client.py', ], ) except subprocess.CalledProcessError as e: - print("Автолинтер не сработал!", e) + print('Автолинтер не сработал!', e) From 02255e0a05f40c67da602f99951cbec986e25d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=BB=20=D0=A7=D0=B8=D1=80=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 31 Jan 2025 16:43:51 +0300 Subject: [PATCH 282/296] --url adding --- src/generator1/generator.py | 70 +- src/generator1/openapi.yaml | 2365 ------------------------------- src/generator1/requirements.txt | 4 +- 3 files changed, 58 insertions(+), 2381 deletions(-) delete mode 100644 src/generator1/openapi.yaml diff --git a/src/generator1/generator.py b/src/generator1/generator.py index e8e8478..456073d 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -1,53 +1,93 @@ +import os.path import subprocess import sys +import os +import requests + MIN_ARGS = 2 COMMAND_INDEX = 1 -GENERATE_COMMAND = 'generate' -INSTALL_TEST_COMMAND = 'test' +GENERATE_COMMAND = "generate" +INSTALL_TEST_COMMAND = "test" +DEFAULT_YAML_URL = ( + "https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml" +) +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +OPENAPI_FILE_PATH = os.path.join(BASE_DIR, "openapi.yaml") def run_command(command): """Функция для выполнения команды в терминале.""" try: subprocess.run(command, check=True, shell=True, text=True) - print(f'Команда выполнена: {command}') + print(f"Команда выполнена: {command}") except subprocess.CalledProcessError as e: print( - f'Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}' + f"Ошибка при выполнении команды: {command}\n" + f"Код ошибки: {e.returncode}\n" + f"Вывод:\n{e.stderr}" ) -def generate_client(): +def download_yaml(url): + """Загрузка YAML файла по URL и сохранение в нужную директорию.""" + print(f"Загрузка YAML файла с {url}...") + try: + response = requests.get(url, timeout=10) + response.raise_for_status() + os.makedirs(os.path.dirname(OPENAPI_FILE_PATH), exist_ok=True) + with open(OPENAPI_FILE_PATH, "wb") as file: + file.write(response.content) + print(f"Файл сохранён тут: {OPENAPI_FILE_PATH}") + except requests.RequestException as e: + print(f"Ошибка при загрузке YAML файла: {e}") + sys.exit(1) + + +def generate_client(yaml_url): """Генерация клиента и запуск скрипта-генератора.""" - print('Генерация клиента...') + download_yaml(yaml_url) + print("Генерация клиента...") run_command( - 'openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite' + f"openapi-python-client generate --path {OPENAPI_FILE_PATH} " + f"--custom-template-path=./templates --overwrite" ) - run_command('python script.py') + run_command("python script.py") def install_and_run_tests(): """Установка пакета и запуск тест-запросов.""" - print('Установка пакета и запуск тест-запросов...') - run_command('pip install ./pachca-api-open-api-3-0-client') - run_command('python pachca.py') + print("Установка пакета и запуск тест-запросов...") + run_command("pip install ./pachca-api-open-api-3-0-client") + run_command("python pachca.py") -if __name__ == '__main__': +if __name__ == "__main__": if len(sys.argv) < MIN_ARGS: - print('Пример команды: python generator.py [generate|test]') + print( + "Пример команды: python generator.py [generate|test] " + "[--url <ссылка на .yaml>]" + ) sys.exit(COMMAND_INDEX) command = sys.argv[COMMAND_INDEX] + yaml_url = DEFAULT_YAML_URL + if "--url" in sys.argv: + url_index = sys.argv.index("--url") + 1 + if url_index < len(sys.argv): + yaml_url = sys.argv[url_index] + else: + print("Ошибка: не указан url после --url") + sys.exit(1) commands = { - GENERATE_COMMAND: generate_client, + GENERATE_COMMAND: lambda: generate_client(yaml_url), INSTALL_TEST_COMMAND: install_and_run_tests, } if command in commands: commands[command]() else: print( - "Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов." + "Некорректный аргумент. Введите 'generate' для генерации клиента " + "или 'test' для запуска тестов." ) sys.exit(COMMAND_INDEX) diff --git a/src/generator1/openapi.yaml b/src/generator1/openapi.yaml deleted file mode 100644 index 939326f..0000000 --- a/src/generator1/openapi.yaml +++ /dev/null @@ -1,2365 +0,0 @@ -openapi: 3.0.3 -info: - title: PachcaAPI - OpenAPI 3.0 - description: Документация к открытому API пачки - version: 3.0.3 -servers: - - url: https://api.pachca.com/api/shared/v1 - -tags: - - name: common methods - description: Everything about common methods - - name: employees - description: Everything about employees - - name: status - description: Everything about - status - - name: tags - description: Everything about - tags - - name: chats and channels - description: Everything about - chats and channels - - name: talk and channel participants - description: Everything about - talk and channel participants - - name: comments - description: Everything about - comments - - name: messages - description: Everything about - messages - - name: reactions to messages - description: Everything about - reactions to messages - - name: reminders - description: Everything about - reminders - -paths: - /custom_properties: - get: - tags: - - common methods - summary: получение списка актульных полей сущности - description: | - Метод для получения актуального списка дополнительных полей участников и напоминаний в вашей компании. Тело запроса отсутствует, параметры передаются в URL (например, /custom_properties?entity_type=User) - operationId: getCommonMethods - parameters: - - name: entity_type - in: query - description: Тип сущности - required: true - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/CommonMethods' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - /uploads: - post: - tags: - - common methods - summary: получения подписи и ключа для загрузки файла - description: | - Данный метод необходимо использовать для загрузки каждого файла. - - Данный метод позволяет получить уникальный набор параметров для загрузки файла. Параметры запроса отсутствуют. - operationId: getUploads - responses: - '200': - description: Успешный ответ. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - /direct_url: - post: - tags: - - common methods - summary: (полученный в ответе на запрос /uploads) загрузка файла - description: | - Данный метод не требует авторизации. - - Получив все параметры, вам необходимо сделать POST запрос в формате multipart/form-data на адрес, который был указан в поле direct_url, отправив полученные параметры и сам файл. - operationId: getDirectUrl - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/DirectResponse' - responses: - '201': - description: При безошибочном выполнении запроса тело ответа отсутствует. - /users: - get: - tags: - - employees - summary: получение актуального списка всех сотрудников компании - description: | - Метод для получения актуального списка сотрудников вашей компании. - Тело запроса отсутствует, параметры передаются в URL (например, /users?per=50&page=2&query=example.com) - operationId: getEmployees - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: query - in: query - description: | - Поисковая фраза для фильтрации результатов (поиск идет по полям first_name (имя), last_name (фамилия), email (электронная почта), phone_number (телефон) и nickname (никнейм)) - required: false - schema: - type: string - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Employee' - /users/{id}: - get: - tags: - - employees - summary: получение информации о сотруднике - description: | - Метод для получения информации о сотруднике. - Для получения сотрудника вам необходимо знать его id и указать его в URL запроса. - operationId: getEmployee - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Employee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /profile/status: - get: - tags: - - status - summary: получение информации о своем статусе - description: | - Метод для получения информации о своем статусе. Параметры запроса отсутствуют. - operationId: getStatus - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - put: - tags: - - status - summary: новый статус - description: | - Метод для установки себе нового статуса. - operationId: putStatus - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - $ref: '#/components/schemas/QueryStatus' - responses: - '200': - description: Объект создан - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Status' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: string - value: string - message: message - code: invalid - payload: {} - wrong_emoji: - description: Emoji статуса не может содержать значения отличные от Emoji символа - value: - errors: - - key: string - value: string - message: message - code: wrong_emoji - payload: {} - delete: - tags: - - status - summary: удаление своего статуса - description: | - Метод для удаления своего статуса. Параметры запроса отсутствуют. - operationId: delStatus - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствует - content: {} - /group_tags/{id}: - get: - tags: - - tags - summary: получение информации о теге - description: | - Метод для получения информации о теге. Названия тегов являются уникальными в компании. - - Для получения тега вам необходимо знать его id и указать его в URL запроса. Параметры запроса отсутствуют - operationId: getTag - parameters: - - name: id - in: path - description: Уникальный идентификатор тега - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /group_tags: - get: - tags: - - tags - summary: получение актуального списка тегов сотрудников - description: | - Метод для получения актуального списка тегов сотрудников. - - Названия тегов являются уникальными в компании. Тело запроса отсутствует, параметры передаются в URL (например, /group_tags?per=10&page=2) - operationId: getTags - parameters: - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /group_tags/{id}/users: - get: - tags: - - tags - operationId: getTagsEmployees - summary: получение актуального списка сотрудников тега - description: | - Метод для получения актуального списка сотрудников тега. - - Идентификатор тега, список сотрудников которого необходимо получить, и другие параметры передаются в URL (например, /group_tags/877650/users?per=3&page=2) - parameters: - - name: id - in: path - description: Уникальный идентификатор сотрудкика - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BaseEmployee' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: exclusion - payload: {} - /chats: - post: - tags: - - chats and channels - operationId: createChat - summary: создание новой беседы или канала - description: | - Метод для создания новой беседы или нового канала. - При создании беседы или канала вы автоматически становитесь участником. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - chat: - $ref: '#/components/schemas/BaseChat' - responses: - '201': - description: Запрос отработал успешно, сущность создана - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - get: - tags: - - chats and channels - operationId: getChats - summary: получение списка бесед и каналов - description: | - Метод для получения списка бесед и каналов по заданным параметрам. - - Тело запроса отсутствует, параметры передаются в URL (например, /chats?per=2&sort[id]=desc) - parameters: - - name: 'sort[id]' - in: query - required: false - description: | - Составной параметр сортировки сущностей выборки. - Варианты значений: по умолчанию desc (по убыванию) или asc (по возрастанию). - На данный момент сортировка доступна только по полю ({field}) id (идентификатор бесед и каналов). - schema: - type: string - enum: - - desc - - asc - default: desc - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - - name: availability - in: query - required: false - description: | - Параметр, который отвечает за доступность и выборку бесед и каналов для пользователя. - Варианты значений: по умолчанию is_member (беседы и каналы, где пользователь является участником) - или public (все открытые беседы и каналы компании, вне зависимости от участия в них пользователя). - schema: - type: string - enum: - - is_member - - public - default: is_member - - name: last_message_at_after - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не раньше чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - - name: last_message_at_before - in: query - required: false - description: | - Фильтрация по времени создания последнего сообщения. - Будут возвращены те беседы/каналы, время последнего созданного сообщения в которых не позже чем указанное (в формате YYYY-MM-DDThh:mm:ss.sssZ). - schema: - type: string - format: date-time - responses: - '200': - description: Запрос отработал как положено, без ошибок - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}: - get: - tags: - - chats and channels - operationId: getChat - summary: получение информации о беседе или канале - description: | - Получения информации о беседе или канале. - Для получения беседы или канала вам необходимо знать её id и указать его в URL запроса. - parameters: - - name: id - description: Идентификатор беседы или канала - in: path - required: true - schema: - type: integer - responses: - '200': - description: Успешный запрос - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Chat' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /chats/{id}/members: - post: - tags: - - talk and channel participants - summary: добавление пользователей в состав участников - description: | - Метод для добавления пользователей в состав участников беседы или канала. - operationId: postMembersToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/members) - Массив идентификаторов пользователей, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/MembersChat' - responses: - '204': - description: Пользователи добавлены - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/group_tags: - post: - tags: - - talk and channel participants - summary: добавление тегов в состав участников беседы или канала - description: | - Метод для добавления тегов в состав участников беседы или канала. - operationId: postTagsToChats - parameters: - - name: id - in: path - description: Идентификатор беседы/канала - required: true - schema: - type: integer - format: int64 - example: 533 - requestBody: - description: | - Идентификатор беседы/канала передаётся в URL (например, /chats/553/group_tags) - Массив идентификаторов тегов, которые станут участниками, передается в теле запроса - content: - application/json: - schema: - $ref: '#/components/schemas/GroupTag' - responses: - '204': - description: Тег(и) добавлен(ы) - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Обязательное поле (не может быть пустым) - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - invalid: - description: Поле не соответствует правилам (пояснения вы получите в поле message) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - '422': - description: С запросом все хорошо, но правила сервиса не позволяют его обработать (например, при попытке создания контакта с уже существующим номером телефона в базе) - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - invalid: - description: Поле имеет неверный формат (идентификатор поля вы получите в поле payload) - value: - errors: - - key: name - value: name - message: message - code: invalid - payload: {} - /chats/{id}/leave: - delete: - tags: - - talk and channel participants - operationId: leaveChat - summary: выход из беседы или канала - description: |- - Метод для самостоятельного выхода из беседы или канала. Параметры запроса отсутствуют/ - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - responses: - '204': - description: При безошибочном выполнении запроса тело ответа отсутствуе - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - personal_chat: - description: Нельзя покинуть персональный чат - value: - errors: - - key: string - value: string - message: message - code: personal_chat - payload: {} - /messages/{id}/thread: - post: - tags: - - comments - summary: создание нового треда - description: | - Метод для создания нового треда к сообщению. Если у сообщения уже был создан тред, то в ответе вернётся информация об уже созданном ранее треде. - operationId: createThread - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения, к которому создается тред. - schema: - type: integer - responses: - '201': - description: Тред успешно создан или возвращены данные существующего треда. - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Thread' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages: - post: - tags: - - messages - summary: создание нового сообщения - description: | - Метод для отправки сообщения в беседу или канал, - личного сообщения пользователю или комментария в тред. - - При использовании entity_type: "discussion" (или просто без указания entity_type) - допускается отправка любого chat_id в поле entity_id. - То есть, сообщение можно отправить зная только идентификатор чата. - При этом, вы имеете возможность отправить сообщение в тред по его идентификатору - или личное сообщение по идентификатору пользователя. - - Для отправки личного сообщения пользователю создавать чат не требуется. - Достаточно указать entity_type: "user" и идентификатор пользователя. - Чат будет создан автоматически, если между вами ещё не было переписки. - Между двумя пользователями может быть только один личный чат. - operationId: createMessage - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/CreateMessage' - responses: - '201': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - messages - summary: получение списка сообщений чата - description: | - Метод для получения списка сообщений бесед, каналов, тредов и личных сообщений. - - Для получения сообщений вам необходимо знать chat_id требуемой беседы, канала, - треда или диалога, и указать его в URL запроса. Сообщения будут возвращены - в порядке убывания даты отправки (то есть, сначала будут идти последние сообщения чата). - Для получения более ранних сообщений чата доступны параметры per и page. - Тело запроса отсутствует, параметры передаются в URL (например, /messages?chat_id=198&per=3) - operationId: getListMessage - parameters: - - name: chat_id - in: query - description: Идентификатор чата (беседа, канал, диалог или чат треда) - required: true - schema: - title: chat_id - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 25, максимум 50) - required: false - schema: - type: integer - default: 25 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Successful - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Message' - example: - data: - - id: 1194277 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Это сообщение тоже попадёт в экспорт - user_id: 12 - created_at: 2023-09-18T13:43:32.000Z - files: [] - buttons: [] - thread: - id: 2633 - chat_id: 44997 - forwarding: null - parent_message_id: null - - id: 1194276 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** добавил **Export bot** в беседу" - user_id: 12 - created_at: 2023-09-18T13:43:27.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - - id: 1194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: "**Andrew** создал беседу" - user_id: 12 - created_at: 2023-09-18T13:43:19.000Z - files: [] - buttons: [] - thread: null - forwarding: null - parent_message_id: null - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}: - get: - tags: - - messages - summary: получение информации о сообщении - description: | - Метод для получения информации о сообщении. - - Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - operationId: getMessage - parameters: - - name: id - in: path - required: true - schema: - title: id - type: integer - responses: - '200': - description: Successfull - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - example: - data: - id: 194275 - entity_type: discussion - entity_id: 198 - chat_id: 198 - content: Вчера мы продали 756 футболок (что на 10% больше, чем в прошлое воскресенье) - user_id: 12 - created_at: 2020-06-08T09:32:57.000Z - files: - - id: 3560 - key: attaches/files/12/21zu7934-02e1-44d9-8df2-0f970c259796/congrat.png - name: congrat.png - file_type: file - url: | - https://pachca-prod-uploads.s3.storage.selcloud.ru/attaches/files/12/21zu7934- - 02e1-44d9-8df2-0f970c259796/congrat.png?response-cache-control=max- - age%3D3600%3B&response-content-disposition=attachment&X-Amz-Algorithm=AWS4-HMAC - -SHA256&X-Amz-Credential=142155_staply%2F20231107%2Fru-1a%2Fs3%2Faws4_ - request&X-Amz-Date=20231107T160412Z&X-Amz-Expires=604800&X-Amz-SignedHeaders= - host&X-Amz-Signature=98765asgfadsfdsaDSd4sdfg35asdf67sadf8 - buttons: [] - thread: - id: 29873 - chat_id: 1949863 - forwarding: null - parent_message_id: 194274 - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - put: - tags: - - messages - operationId: editMessage - summary: редактирование сообщения по указанному идентификатору - description: Метод для редактирования сообщения или комментария. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор беседы или канала. - schema: - type: integer - requestBody: - description: Массив идентификаторов тегов, которые станут участниками - content: - application/json: - schema: - type: object - properties: - message: - $ref: '#/components/schemas/EditMessages' - responses: - '200': - description: Успешно отредактировано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Message' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /messages/{id}/reactions: - post: - tags: - - reactions to messages - operationId: postMessageReactions - summary: добавление реакции - description: > - Метод для добавления реакции на сообщение. - **Лимиты реакций:** - - Каждый пользователь может установить не более 20 уникальных реакций на сообщение. - - Сообщение может иметь не более 30 уникальных реакций. - - Сообщение может иметь не более 1000 реакций. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CodeReaction' - responses: - "201": - description: Успешное выполнение запроса, тело ответа отсутствует. - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - user_limit: - description: Превышен лимит уникальных реакций пользователя - value: - errors: - - key: string - value: string - message: Вы можете добавить не более 20 уникальных реакций. - code: user_limit - payload: {} - unique_limit: - description: Превышен лимит уникальных реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 30 уникальных реакций. - code: unique_limit - payload: {} - general_limit: - description: Превышен общий лимит реакций на сообщение - value: - errors: - - key: string - value: string - message: Сообщение может содержать не более 1000 реакций. - code: general_limit - payload: {} - delete: - tags: - - reactions to messages - operationId: deleteMessageReactions - summary: удаление реакции - description: > - Метод для удаления реакции на сообщение. - Удалить можно только те реакции, которые были поставлены авторизованным пользователем. - parameters: - - name: id - in: path - required: true - description: Уникальный идентификатор сообщения. - schema: - type: integer - - name: code - in: query - description: Emoji в строковом формате для добавления реакции. - schema: - type: string - example: "👍" - responses: - "204": - description: При безошибочном выполнении запроса тело ответа отсутствует - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: name - value: '' - message: message - code: blank - payload: {} - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - get: - tags: - - reactions to messages - operationId: getMessageReactions - summary: получение актуального списка реакций - description: | - Метод для получения актуального списка реакций на сообщение. - - Идентификатор сообщения, список реакций на которое необходимо получить, передается в URL (например, /messages/7231942/reactions). Количество возвращаемых сущностей и страница выборки указываются в теле запроса - parameters: - - name: id - in: path - description: Уникальный идентификатор сообщения - required: true - schema: - type: integer - - name: per - in: query - description: Количество возвращаемых сущностей за один запрос (по умолчанию 50, максимум 50) - required: false - schema: - type: integer - default: 50 - maximum: 50 - - name: page - in: query - description: Страница выборки (по умолчанию 1) - required: false - schema: - type: integer - default: 1 - responses: - '200': - description: Список реакций успешно получен. - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/Reaction' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - exclusion: - description: Поле имеет недопустимое значение - value: - errors: - - key: name - value: 1234 - message: message - code: exclusion - payload: {} - not_found: - description: Не удалось найти - value: - errors: - - key: string - value: string - message: message - code: not_found - payload: {} - /tasks: - post: - tags: - - reminders - operationId: createTask - summary: создание нового напоминания - description: | - Метод для создания нового напоминания. - - При создании напоминания обязательным условием является указания типа напоминания: звонок, встреча, простое напоминание, событие или письмо. - При этом не требуется дополнительное описание - вы просто создадите напоминание с соответствующим текстом. - Если вы укажите описание напоминания - то именно оно и станет текстом напоминания. - У напоминания должны быть ответственные, если их не указывать - ответственным назначаетесь вы. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - task: - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания (call, meeting, reminder, event, email) - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - responses: - '201': - description: Напоминание успешно создано - content: - application/json: - schema: - type: object - properties: - data: - $ref: '#/components/schemas/Task' - '400': - description: Пояснения ошибки - content: - application/json: - schema: - $ref: '#/components/schemas/Errors' - examples: - blank: - description: Поле не может быть пустым - value: - errors: - - key: string - value: string - message: message - code: blank - payload: {} - too_long: - description: Слишком длинное значение (пояснения вы получите в поле message) - value: - errors: - - key: name - value: long_name - message: message - code: too_long - payload: {} - inclusion: - description: Поле имеет непредусмотренное значение - value: - errors: - - key: string - value: string - message: message - code: inclusion - payload: {} - invalid: - description: Поле имеет неверное значение (например, указаны недопустимые ответственные) - value: - errors: - - key: name - value: 1234 - message: message - code: invalid - payload: {} -components: - schemas: - MembersChat: - title: Members Chat - required: - - member_ids - type: object - properties: - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - minItems: 1 - items: - type: integer - format: int64 - example: [186, 187] - silent: - type: boolean - description: Не создавать в чате системное сообщение о добавлении участника - GroupTag: - title: Group Tag - required: - - group_tag_ids - type: object - properties: - group_tag_ids: - type: array - minItems: 1 - items: - type: integer - format: int64 - example: [86, 18] - description: Массив идентификаторов тегов, которые станут участниками - CodeReaction: - title: Code Reaction - type: object - properties: - code: - type: string - example: "👍" - description: Emoji в строковом формате для добавления реакции. - required: - - code - BaseEmployee: - title: Base Employee - type: object - properties: - id: - type: integer - example: 1 - description: Идентификатор пользователя - first_name: - type: string - description: Имя - last_name: - type: string - description: Фамилия - nickname: - type: string - description: Имя пользователя - email: - type: string - description: Электронная почта - phone_number: - type: string - description: Телефон - department: - type: string - description: Департамент - role: - type: string - enum: - - admin - - user - - multi_guest - description: | - Уровень доступа: admin (администратор), user (сотрудник), multi_guest (мульти-гость) - suspended: - type: boolean - description: | - Деактивация пользователя. При значении true пользователь является деактивированным. - invite_status: - type: string - enum: - - confirmed - - sent - description: | - Статус приглашения: confirmed (принято), sent (отправлено) - list_tags: - type: array - items: - type: string - description: Массив тегов, привязанных к сотруднику - custom_properties: - type: array - description: Дополнительные поля сотрудника - items: - type: object - properties: - id: - type: integer - description: Идентификатор поля - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - value: - type: string - description: Значение - bot: - type: boolean - description: | - Тип: пользователь (false) или бот (true) - description: Базовый класс сотрудника. - Employee: - allOf: - - $ref: '#/components/schemas/BaseEmployee' - - type: object - properties: - user_status: - $ref: '#/components/schemas/Status' - title: - type: string - description: Должность - created_at: - type: string - format: date-time - description: | - Дата создания (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - time_zone: - type: string - description: Часовой пояс пользователя - image_url: - type: string - nullable: true - description: Ссылка на скачивание аватарки - description: Расширенный класс сотрудника. - BaseResponse: - title: Base Response - type: object - properties: - Content-Disposition: - type: string - description: Используемый заголовок - default: attachment - acl: - type: string - description: Уровень безопасности - default: private - policy: - type: string - description: Уникальный policy для загрузки файла - x-amz-credential: - type: string - description: x-amz-credential для загрузки файла - x-amz-algorithm: - type: string - description: Используемый алгоритм - default: AWS4-HMAC-SHA256 - x-amz-date: - type: string - description: Уникальный x-amz-date для загрузки файла - x-amz-signature: - type: string - description: Уникальная подпись для загрузки файла - key: - type: string - description: Уникальный ключ для загрузки файла - FileResponse: - title: File Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - direct_url: - type: string - description: Адрес для загрузки файла - DirectResponse: - title: Direct Response - allOf: - - $ref: '#/components/schemas/BaseResponse' - - type: object - properties: - file: - type: string - description: Адрес для загрузки файла - Status: - type: object - nullable: true - description: Статус. Возвращается как null, если статус не установлен. - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - nullable: true - description: | - Срок жизни статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. Возвращается как null, если срок не установлен. - QueryStatus: - type: object - properties: - status: - type: object - description: Собранный объект параметров нового статуса - required: - - emoji - - title - properties: - emoji: - type: string - description: Emoji символ статуса - title: - type: string - description: Текст статуса - expires_at: - type: string - format: date-time - description: Срок действия статуса (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - nullable: true - CommonMethods: - title: Common Methods - type: object - description: получение списка актульных полей сущности. - properties: - id: - type: integer - example: 1 - description: Название поля - name: - type: string - example: Дата рождения - description: Идентификатор поля - data_type: - type: string - enum: - - string - - number - - date - - link - example: number - description: тип поля - Errors: - type: object - properties: - errors: - type: array - items: - key: - title: key - type: string - description: Ключ параметра, в котором произошла ошибка - value: - title: value - type: string - description: Значение ключа, которое вызвало ошибку - message: - title: message - type: string - description: Ошибка текстом, который вы можете вывести пользователю - code: - title: code - type: string - description: Внутренний код ошибки (коды ошибок представлены в описании каждого метода) - payload: - title: payload - type: object - description: Объект, который предоставляет любую дополнительную информацию (возможные дополнения представлены в описании каждого метода) - Buttons: - title: Message Buttons - type: array - maxItems: 100 - items: - title: Row Buttons - type: array - maxItems: 8 - items: - type: object - title: Button - required: - - text - minProperties: 2 - properties: - text: - title: Text - type: string - maxLength: 255 - url: - title: Url - type: string - data: - title: Data - type: string - maxLength: 255 - BaseThread: - title: Base Thread - type: object - properties: - id: - type: integer - description: Идентификатор поля - chat_id: - type: integer - description: Идентификатор поля чата - Thread: - allOf: - - $ref: '#/components/schemas/BaseThread' - - type: object - properties: - message_id: - type: integer - description: Идентификатор сообщения, к которому был создан тред. - message_chat_id: - type: integer - description: Идентификатор чата сообщения. - updated_at: - type: string - format: date-time - description: | - Дата и время обновления треда (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - BaseFiles: - title: Base Files - type: object - required: - - key - - name - - file_type - properties: - key: - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - type: string - enum: - - file - - image - CreateEditFiles: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Create&Edit Files - required: - - size - properties: - size: - type: integer - description: Размер файла в байтах, отображаемый пользователю - Files: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseFiles' - - type: object - title: Files - properties: - id: - type: integer - description: Идентификатор поля - url: - type: string - description: Прямая временная ссылка на скачивание файла - BeforeBaseMessages: - title: Before Base Messages - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - content: - type: string - description: Текст сообщения - default: Текст сообщения - buttons: - allOf: - - $ref: '#/components/schemas/Buttons' - title: buttons - EditMessages: - title: Edit Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - description: Для получения сообщения вам необходимо знать его id и указать его в URL запроса. - required: - - content - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - BaseMessages: - title: Base Messages - allOf: - - $ref: '#/components/schemas/BeforeBaseMessages' - - type: object - required: - - entity_id - properties: - entity_type: - title: Entity Type - type: string - enum: - - discussion - - user - - thread - default: discussion - entity_id: - title: Entity Id - type: integer - parent_message_id: - title: Parent Massage Id - type: integer - nullable: true - default: null - description: Идентификатор сообщения, к которому написан ответ. Возвращается как null, если сообщение не является ответом. - CreateMessage: - title: Create Messages - allOf: - - $ref: '#/components/schemas/BaseMessages' - - type: object - properties: - files: - allOf: - - $ref: '#/components/schemas/CreateEditFiles' - title: files - skip_invite_mentions: - title: Skip Invite Mentions - type: boolean - default: false - link_preview: - title: Link Preview - type: boolean - default: false - Message: - type: object - properties: - entity_type: - title: Entity Type - type: string - enum: - - 'discussion' - - 'user' - - 'thread' - default: 'discussion' - entity_id: - title: Entity Id - type: integer - content: - title: Content - type: string - id: - title: Id - type: integer - chat_id: - title: Chat Id - type: integer - user_id: - title: User Id - type: integer - created_at: - title: Created At - type: string - format: date-time - files: - title: Files - type: array - items: - type: object - properties: - id: - title: Id - type: integer - key: - title: Key - type: string - description: Путь к файлу, полученный в результате загрузки файла (каждый файл в каждом сообщении должен иметь свой уникальный key, не допускается использование одного и того же key в разных сообщениях) - name: - title: Name - type: string - description: Название файла, которое вы хотите отображать пользователю (рекомендуется писать вместе с расширением) - file_type: - title: File Type - type: string - enum: - - 'file' - - 'image' - url: - title: Url - type: string - description: Размер файла в байтах, отображаемый пользователю - Reaction: - type: object - properties: - user_id: - type: integer - description: | - Идентификатор пользователя, оставившего реакцию. - created_at: - type: string - format: date-time - description: | - Дата и время добавления реакции (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ. - code: - type: string - description: | - Emoji символ реакции. - BaseChat: - title: Base Chat - type: object - description: Собранный объект параметров создаваемой беседы или канала - required: - - name - properties: - name: - type: string - description: Название - example: 🤿 aqua - member_ids: - type: array - description: Массив идентификаторов пользователей, которые станут участниками - items: - type: integer - example: - - 186 - - 187 - group_tag_ids: - type: array - description: Массив идентификаторов тегов, участников - items: - type: integer - example: [] - channel: - type: boolean - description: 'Тип: беседа (по умолчанию, false) или канал (true)' - example: true - public: - type: boolean - description: 'Доступ: закрытый (по умолчанию, false) или открытый (true)' - example: false - Chat: - allOf: - - type: object - properties: - id: - type: integer - description: Идентификатор беседы или канала - example: 334 - owner_id: - type: integer - description: Идентификатор пользователя, создавшего беседу или канал - example: 185 - created_at: - type: string - format: date-time - description: Дата и время создания беседы или канала (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:56:53.000Z' - last_message_at: - type: string - format: date-time - description: Дата и время создания последнего сообщения в беседе/канале (ISO-8601, UTC+0) в формате YYYY-MM-DDThh:mm:ss.sssZ - example: '2021-08-28T15:58:13.000Z' - meet_room_url: - type: string - description: Ссылка на Видеочат - example: 'https://meet.pachca.com/aqua-94bb21b5' - - $ref: '#/components/schemas/BaseChat' - Tag: - type: object - description: Для получения тега вам необходимо знать его id и указать его в URL запроса. - properties: - id: - type: integer - description: Идентификатор тега - name: - type: string - description: Название тега - users_count: - description: Количество сотрудников, которые имеют этот тег - type: integer - BaseCustomProperties: - title: Base Custom Properties - description: Задаваемые дополнительные поля - type: object - properties: - id: - type: integer - description: Идентификатор поля - value: - type: string - description: Значение поля - CustomProperties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - - type: object - title: Custom Properties - properties: - name: - type: string - description: Название поля - data_type: - type: string - enum: - - string - - number - - date - - link - description: Тип поля (string, number, date или link) - BaseTask: - title: Base Task - type: object - required: - - kind - - content - - due_at - properties: - kind: - type: string - description: Тип напоминания - enum: - - call - - meeting - - reminder - - event - - email - content: - type: string - description: Описание напоминания - due_at: - type: string - format: date-time - description: Срок выполнения напоминания (ISO-8601) - priority: - type: integer - description: Приоритет (1 - по умолчанию, 2 - важно, 3 - очень важно) - enum: - - 1 - - 2 - - 3 - performer_ids: - type: array - items: - type: integer - description: Массив идентификаторов пользователей - custom_properties: - type: array - items: - allOf: - - $ref: '#/components/schemas/BaseCustomProperties' - Task: - allOf: - - $ref: '#/components/schemas/BaseTask' - - type: object - properties: - id: - type: integer - description: Идентификатор созданного напоминания - user_id: - type: integer - description: Идентификатор пользователя-создателя - status: - type: string - description: Статус напоминания - created_at: - type: string - format: date-time - description: Дата и время создания - custom_properties: - allOf: - - $ref: '#/components/schemas/CustomProperties' - securitySchemes: - bearerAuth: - type: http - scheme: bearer -security: - - bearerAuth: [] diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index 1112cd7..afe2831 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -10,4 +10,6 @@ ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 typing_extensions==4.12.2 black==24.10.0 -isort==5.13.2 \ No newline at end of file +isort==5.13.2 +requests +python-dotenv \ No newline at end of file From fe3a95d9e9512beea723dd9b228cb25f324aedb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Sat, 1 Feb 2025 22:41:45 +0300 Subject: [PATCH 283/296] first_fixed --- src/generator1/generator.py | 41 +----- src/generator1/pachca.py | 23 +-- src/generator1/pydantic_script.py | 40 ++++++ src/generator1/requirements.txt | 4 +- src/generator1/templates/model.py.jinja | 181 ++++++++++++++++++++++++ 5 files changed, 237 insertions(+), 52 deletions(-) create mode 100644 src/generator1/pydantic_script.py create mode 100644 src/generator1/templates/model.py.jinja diff --git a/src/generator1/generator.py b/src/generator1/generator.py index 9164b86..e13e8bd 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -19,6 +19,7 @@ def generate_client(): """Генерация клиента и запуск скрипта-генератора.""" print("Генерация клиента...") run_command("openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite") + run_command("python pydantic_script.py") run_command("python script.py") def install_and_run_tests(): @@ -42,43 +43,3 @@ def install_and_run_tests(): else: print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") sys.exit(COMMAND_INDEX) - - - -# import subprocess -# import sys - -# def run_command(command): -# """Функция для выполнения команды в терминале.""" -# try: -# subprocess.run(command, check=True, shell=True, text=True) -# print(f"Команда выполнена: {command}") -# except subprocess.CalledProcessError as e: -# print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") - -# def generate_client(): -# """Генерация клиента и запуск скрипта-генератора.""" -# print("Генерация клиента...") -# run_command("openapi-python-client generate --path openapi.yaml --custom-template-path=./templates --overwrite") -# run_command("python script.py") - -# def install_and_run_tests(): -# """Установка пакета и запуск тест-запросов.""" -# print("Установка пакета и запуск тест-запросов...") -# run_command("pip install ./pachca-api-open-api-3-0-client") -# run_command("python pachca.py") - -# if __name__ == "__main__": -# if len(sys.argv) != 2: -# print("Пример команды: python generator.py [generate|test]") -# sys.exit(1) - -# option = sys.argv[1] - -# if option == "generate": -# generate_client() -# elif option == "test": -# install_and_run_tests() -# else: -# print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") -# sys.exit(1) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index baac452..fe32491 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -45,6 +45,7 @@ async def main() -> None: """ Функция теста эндпоинтов """ + # import pdb;pdb.set_trace() # подготовка запроса на создание беседы --> query_chat = BaseChat(name='test500_2') @@ -127,20 +128,20 @@ async def main() -> None: ) # запрос на получения списка пользователей - users_response = await asyncio.create_task(pachca.getEmployees()) + # users_response = await asyncio.create_task(pachca.getEmployees()) # запрос на получение информации о пользователе - getEmployee = await asyncio.create_task( - pachca.getEmployee(id=users_response.data[0].id) - ) + # getEmployee = await asyncio.create_task( + # pachca.getEmployee(id=users_response.data[0].id) + # ) # подготовка запроса на добавление участника --> - chats_body = MembersChat(member_ids=[users_response.data[0].id]) + # chats_body = MembersChat(member_ids=[users_response.data[0].id]) # <-- # запрос на добавление участника в беседу - postMembersToChats = await asyncio.create_task(pachca.postMembersToChats( - id=chat_response.data.id, body=chats_body) - ) + # postMembersToChats = await asyncio.create_task(pachca.postMembersToChats( + # id=chat_response.data.id, body=chats_body) + # ) # подготовка запроса на добавление статуса --> query_status = QueryStatusStatus( @@ -209,9 +210,9 @@ async def main() -> None: getMessageReactions, deleteMessageReactions, createtaskbody, - users_response, - getEmployee, - postMembersToChats, + # users_response, + # getEmployee, + # postMembersToChats, putStatus, getStatus, delStatus, diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py new file mode 100644 index 0000000..17751f7 --- /dev/null +++ b/src/generator1/pydantic_script.py @@ -0,0 +1,40 @@ +import os + +def correcting_imports_in_model_files(file_path): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.readlines() + + new_content = [] + skip_next_lines = False + + for line in content: + # Проверяем, является ли строка условием TYPE_CHECKING + if line.strip() == 'if TYPE_CHECKING:': + skip_next_lines = True + continue # Пропускаем эту строку + + # Если мы пропускаем строки, значит это импорты + if skip_next_lines: + if line.strip(): # Если строка не пустая + new_content.append(line.lstrip()) # Сдвигаем влево + else: + new_content.append(line) # Добавляем строку как есть + + # Если встретили пустую строку, значит закончили с импортами + if line.strip() == '': + skip_next_lines = False + + # Записываем изменения обратно в файл + with open(file_path, 'w', encoding='utf-8') as file: + file.writelines(new_content) + +def changes_all_model_files(directory): + for filename in os.listdir(directory): + if filename.endswith('.py'): + correcting_imports_in_model_files(os.path.join(directory, filename)) + +changes_all_model_files( + "./pachca-api-open-api-3-0-client/" + "pachca_api_open_api_3_0_client/" + "models/" +) diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index 1112cd7..1c81f0a 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -10,4 +10,6 @@ ruamel.yaml==0.18.6 ruamel.yaml.clib==0.2.12 typing_extensions==4.12.2 black==24.10.0 -isort==5.13.2 \ No newline at end of file +isort==5.13.2 +pydantic==2.10.4 +pydantic_core==2.27.2 diff --git a/src/generator1/templates/model.py.jinja b/src/generator1/templates/model.py.jinja new file mode 100644 index 0000000..f535384 --- /dev/null +++ b/src/generator1/templates/model.py.jinja @@ -0,0 +1,181 @@ +from typing import Any, TypeVar, Optional, BinaryIO, TextIO, TYPE_CHECKING, Dict + +from pydantic import BaseModel, Field +{% if model.is_multipart_body %} +import json +{% endif %} + +from ..types import UNSET, Unset + +{% for relative in model.relative_imports | sort %} +{{ relative }} +{% endfor %} + +{% for lazy_import in model.lazy_imports %} +{% if loop.first %} +if TYPE_CHECKING: +{% endif %} + {{ lazy_import }} +{% endfor %} + +{% if model.additional_properties %} +{% set additional_property_type = 'Any' if model.additional_properties == True else model.additional_properties.get_type_string(quoted=not model.additional_properties.is_base_type) %} +{% endif %} + +{% set class_name = model.class_info.name %} +{% set module_name = model.class_info.module_name %} + +{% from "helpers.jinja" import safe_docstring %} + +T = TypeVar("T", bound="{{ class_name }}") + +{% macro class_docstring_content(model) %} + {% if model.title %}{{ model.title | wordwrap(116) }} + + {% endif -%} + {%- if model.description %}{{ model.description | wordwrap(116) }} + + {% endif %} + {% if not model.title and not model.description %} + {# Leave extra space so that a section doesn't start on the first line #} + + {% endif %} + {% if model.example %} + Example: + {{ model.example | string | wordwrap(112) | indent(12) }} + + {% endif %} + {% if model.required_properties or model.optional_properties %} + Attributes: + {% for property in model.required_properties + model.optional_properties %} + {{ property.to_docstring() | wordwrap(112) | indent(12) }} + {% endfor %}{% endif %} +{% endmacro %} + +class {{ class_name }}(BaseModel): + {{ safe_docstring(class_docstring_content(model)) | indent(4) }} + + {% for property in model.required_properties + model.optional_properties %} + {{ property.to_string() }} + {% endfor %} + {% if model.additional_properties %} + additional_properties: dict[str, {{ additional_property_type }}] = Field(default_factory=dict) + {% endif %} + class Config: + arbitrary_types_allowed = True + +{% macro _to_dict(multipart=False) %} +{% for property in model.required_properties + model.optional_properties %} +{% import "property_templates/" + property.template as prop_template %} +{% if multipart %} +{{ prop_template.transform_multipart(property, "self." + property.python_name, property.python_name) }} +{% elif prop_template.transform %} +{{ prop_template.transform(property=property, source="self." + property.python_name, destination=property.python_name) }} +{% else %} +{{ property.python_name }} = self.{{ property.python_name }} +{% endif %} + +{% endfor %} + +field_dict: dict[str, Any] = {} +{% if model.additional_properties %} +{% import "property_templates/" + model.additional_properties.template as prop_template %} +{% if multipart %} +for prop_name, prop in self.additional_properties.items(): + {{ prop_template.transform_multipart(model.additional_properties, "prop", "field_dict[prop_name]") | indent(4) }} +{% elif prop_template.transform %} +for prop_name, prop in self.additional_properties.items(): + {{ prop_template.transform(model.additional_properties, "prop", "field_dict[prop_name]", declare_type=false) | indent(4) }} +{% else %} +field_dict.update(self.additional_properties) +{% endif %} +{% endif %} + +{% if model.required_properties | length > 0 or model.optional_properties | length > 0 %} +field_dict.update({ + {% for property in model.required_properties + model.optional_properties %} + {% if property.required %} + "{{ property.name }}": {{ property.python_name }}, + {% endif %} + {% endfor %} +}) +{% endif %} +{% for property in model.optional_properties %} +{% if not property.required %} +if {{ property.python_name }} is not UNSET: + field_dict["{{ property.name }}"] = {{ property.python_name }} +{% endif %} +{% endfor %} + +return field_dict +{% endmacro %} + + def to_dict(self) -> dict[str, Any]: + {% for lazy_import in model.lazy_imports %} + {{ lazy_import }} + {% endfor %} + {{ _to_dict() | indent(8) }} + +{% if model.is_multipart_body %} + def to_multipart(self) -> dict: + {{ _to_dict(multipart=True) | indent(8) }} +{% endif %} + + @classmethod + def from_dict(cls, src_dict: dict) -> "{{ class_name }}": + {% for lazy_import in model.lazy_imports %} + {{ lazy_import }} + {% endfor %} +{% if (model.required_properties or model.optional_properties or model.additional_properties) %} + d = src_dict.copy() +{% for property in model.required_properties + model.optional_properties %} + {% if property.required %} + {% set property_source = 'd.pop("' + property.name + '")' %} + {% else %} + {% set property_source = 'd.pop("' + property.name + '", UNSET)' %} + {% endif %} + {% import "property_templates/" + property.template as prop_template %} + {% if prop_template.construct %} + {{ prop_template.construct(property, property_source) | indent(8) }} + {% else %} + {{ property.python_name }} = {{ property_source }} + {% endif %} + +{% endfor %} +{% endif %} + {{ module_name }} = cls( +{% for property in model.required_properties + model.optional_properties %} + {{ property.python_name }}={{ property.python_name }}, +{% endfor %} + ) + +{% if model.additional_properties %} + {% if model.additional_properties.template %}{# Can be a bool instead of an object #} + {% import "property_templates/" + model.additional_properties.template as prop_template %} + +{% if model.additional_properties.lazy_imports %} + {% for lazy_import in model.additional_properties.lazy_imports %} + {{ lazy_import }} + {% endfor %} +{% endif %} + {% else %} + {% set prop_template = None %} + {% endif %} + {% if prop_template and prop_template.construct %} + additional_properties = {} + for prop_name, prop_dict in d.items(): + {{ prop_template.construct(model.additional_properties, "prop_dict") | indent(12) }} + additional_properties[prop_name] = {{ model.additional_properties.python_name }} + + {{ module_name }}.additional_properties = additional_properties + {% else %} + {{ module_name }}.additional_properties = d + {% endif %} +{% endif %} + return {{ module_name }} + + {% if model.additional_properties %} + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + {% endif %} From 2cca87d12cc9f84a2adae0bdec36e0170b97e046 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 4 Feb 2025 00:25:57 +0300 Subject: [PATCH 284/296] formatter --- src/generator1/pydantic_script.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py index 17751f7..74118be 100644 --- a/src/generator1/pydantic_script.py +++ b/src/generator1/pydantic_script.py @@ -1,9 +1,10 @@ import os + def correcting_imports_in_model_files(file_path): with open(file_path, 'r', encoding='utf-8') as file: content = file.readlines() - + new_content = [] skip_next_lines = False @@ -28,13 +29,15 @@ def correcting_imports_in_model_files(file_path): with open(file_path, 'w', encoding='utf-8') as file: file.writelines(new_content) + def changes_all_model_files(directory): for filename in os.listdir(directory): if filename.endswith('.py'): - correcting_imports_in_model_files(os.path.join(directory, filename)) + correcting_imports_in_model_files( + os.path.join(directory, filename) + ) + changes_all_model_files( - "./pachca-api-open-api-3-0-client/" - "pachca_api_open_api_3_0_client/" - "models/" + './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/', ) From 7cef3443766a664f324f13a5c8181901c3e01b9a Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 4 Feb 2025 00:44:34 +0300 Subject: [PATCH 285/296] update README for gen1 and update requirements --- src/generator1/README.md | 7 +++++++ src/generator1/requirements.txt | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/generator1/README.md b/src/generator1/README.md index 5f6070b..00e529f 100644 --- a/src/generator1/README.md +++ b/src/generator1/README.md @@ -9,6 +9,13 @@ pip install -r requirements.txt python generator.py generate +2.1 По желанию можно указать именованный аргумент --url, +с указанием ссылки на спецификацию, по которой будет происходить генерация клиента. +Если не указывать, то будет взята официальная спецификация от Пачки по адресу: +https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml + +python generator.py generate --url *ссылка на YAML спецификацию* + 3. Запустить скрипт-пример запроса python generator.py test diff --git a/src/generator1/requirements.txt b/src/generator1/requirements.txt index 249a24f..8b2158e 100644 --- a/src/generator1/requirements.txt +++ b/src/generator1/requirements.txt @@ -13,5 +13,5 @@ black==24.10.0 isort==5.13.2 pydantic==2.10.4 pydantic_core==2.27.2 -requests -python-dotenv +requests==2.32.3 +python-dotenv==1.0.1 From 25a054f4795b6d72f1634e82a065fa6304e09f55 Mon Sep 17 00:00:00 2001 From: SanyM2007 Date: Tue, 11 Feb 2025 02:04:56 +0500 Subject: [PATCH 286/296] library ver1 --- src/builder/MANIFEST.in | 1 + src/builder/Makefile | 5 +- src/builder/Pipfile | 49 +- src/builder/Pipfile.lock | 515 ++++++------------ src/builder/README.md | 7 +- src/builder/requirements.txt | 60 +- src/builder/{setup_generator1.py => setup.py} | 26 +- src/builder/setup_generator2.py | 43 -- src/generator1/__init__.py | 0 src/generator1/api_generator.py | 32 ++ src/generator1/generator.py | 45 +- src/generator1/pachca.py | 39 +- src/generator1/pydantic_script.py | 20 +- src/generator1/script.py | 137 ++--- src/generator1/templates/__init__.py | 0 src/generator1/templates/macros/__init__.py | 0 src/generator2/generate_pydantic_model.py | 5 +- .../generator2_full/logger_setup.py | 3 +- src/generator2/request_methods_generator.py | 5 +- src/generator2/services/constants.py | 2 +- src/generator2/services/yaml_loader.py | 1 - src/generator2/yaml_processor.py | 9 +- .../PachcaAPI-0.0.39-py3-none-any.whl | Bin 0 -> 22867 bytes .../pachca_generator1-0.2.3-py3-none-any.whl | Bin 129056 -> 0 bytes .../pachca_generator2-0.2.3-py3-none-any.whl | Bin 137582 -> 0 bytes 25 files changed, 343 insertions(+), 661 deletions(-) create mode 100644 src/builder/MANIFEST.in rename src/builder/{setup_generator1.py => setup.py} (61%) delete mode 100644 src/builder/setup_generator2.py create mode 100644 src/generator1/__init__.py create mode 100644 src/generator1/api_generator.py create mode 100644 src/generator1/templates/__init__.py create mode 100644 src/generator1/templates/macros/__init__.py create mode 100644 src/repository/PachcaAPI-0.0.39-py3-none-any.whl delete mode 100644 src/repository/pachca_generator1-0.2.3-py3-none-any.whl delete mode 100644 src/repository/pachca_generator2-0.2.3-py3-none-any.whl diff --git a/src/builder/MANIFEST.in b/src/builder/MANIFEST.in new file mode 100644 index 0000000..9d1fa63 --- /dev/null +++ b/src/builder/MANIFEST.in @@ -0,0 +1 @@ +recursive-include ../generator1/templates * \ No newline at end of file diff --git a/src/builder/Makefile b/src/builder/Makefile index dc95cce..3b74882 100644 --- a/src/builder/Makefile +++ b/src/builder/Makefile @@ -16,11 +16,10 @@ test: build: clean - python setup_generator1.py bdist_wheel --dist-dir=../repository/ - python setup_generator2.py bdist_wheel --dist-dir=../repository/ + python setup.py bdist_wheel --dist-dir=../repository/ clean: - @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ ../repository/ + @rm -rf .pytest_cache/ .mypy_cache/ junit/ build/ ../repository/ ../*.egg-info/ .PHONY: upload upload: build diff --git a/src/builder/Pipfile b/src/builder/Pipfile index e984d06..82faf0d 100644 --- a/src/builder/Pipfile +++ b/src/builder/Pipfile @@ -4,51 +4,22 @@ verify_ssl = true name = "pypi" [packages] -annotated-types = "==0.7.0" anyio = "==4.7.0" attrs = "==24.3.0" -black = "==24.10.0" -certifi = "==2024.12.14" -cfgv = "==3.4.0" -chardet = "==5.2.0" -charset-normalizer = "==3.4.1" -click = "==8.1.8" -colorama = "==0.4.6" -distlib = "==0.3.9" -exceptiongroup = "==1.2.2" -filelock = "==3.16.1" -h11 = "==0.14.0" httpcore = "==1.0.7" -httpx = "==0.28.1" -identify = "==2.6.4" -idna = "==3.10" -jsonschema = "==4.23.0" -jsonschema-spec = "==0.2.4" -jsonschema-specifications = "==2023.7.1" -lazy-object-proxy = "==1.10.0" -mypy-extensions = "==1.0.0" -nodeenv = "==1.9.1" -packaging = "==24.2" -pathable = "==0.4.3" -pathspec = "==0.12.1" -platformdirs = "==4.3.6" -prance = "==23.6.21.0" -pre-commit = "==3.8.0" +httpx = "==0.27.2" +jinja2 = "==3.1.4" +openapi-python-client = "==0.22.0" +pyyaml = "==6.0.2" +"ruamel.yaml" = "==0.18.6" +"ruamel.yaml.clib" = "==0.2.12" +typing-extensions = "==4.12.2" +black = "==24.10.0" +isort = "==5.13.2" pydantic = "==2.10.4" pydantic-core = "==2.27.2" -python-dotenv = "==1.0.1" -pyyaml = "==6.0.2" -referencing = "==0.30.2" requests = "==2.32.3" -rfc3339-validator = "==0.1.4" -rpds-py = "==0.22.3" -ruff = "==0.7.1" -six = "==1.17.0" -sniffio = "==1.3.1" -tomli = "==2.2.1" -typing-extensions = "==4.12.2" -urllib3 = "==2.3.0" -virtualenv = "==20.28.1" +python-dotenv = "==1.0.1" [dev-packages] diff --git a/src/builder/Pipfile.lock b/src/builder/Pipfile.lock index 3517501..3e652d9 100644 --- a/src/builder/Pipfile.lock +++ b/src/builder/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "744e7f7d38ac30aef12af9aaeb5d321d2b27751994f15b7dde921e6b6abee73f" + "sha256": "d74747f4b36f5701f892b052e2e03554226c99eac8761289805a434f76846737" }, "pipfile-spec": 6, "requires": { @@ -21,7 +21,6 @@ "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" ], - "index": "pypi", "markers": "python_version >= '3.8'", "version": "==0.7.0" }, @@ -74,30 +73,11 @@ }, "certifi": { "hashes": [ - "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", - "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" ], - "index": "pypi", "markers": "python_version >= '3.6'", - "version": "==2024.12.14" - }, - "cfgv": { - "hashes": [ - "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", - "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==3.4.0" - }, - "chardet": { - "hashes": [ - "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", - "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==5.2.0" + "version": "==2025.1.31" }, "charset-normalizer": { "hashes": [ @@ -194,7 +174,6 @@ "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" ], - "index": "pypi", "markers": "python_version >= '3.7'", "version": "==3.4.1" }, @@ -203,7 +182,6 @@ "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" ], - "index": "pypi", "markers": "python_version >= '3.7'", "version": "==8.1.8" }, @@ -212,42 +190,14 @@ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" ], - "index": "pypi", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", "version": "==0.4.6" }, - "distlib": { - "hashes": [ - "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", - "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403" - ], - "index": "pypi", - "version": "==0.3.9" - }, - "exceptiongroup": { - "hashes": [ - "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", - "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.2.2" - }, - "filelock": { - "hashes": [ - "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", - "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==3.16.1" - }, "h11": { "hashes": [ "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" ], - "index": "pypi", "markers": "python_version >= '3.7'", "version": "==0.14.0" }, @@ -262,144 +212,152 @@ }, "httpx": { "hashes": [ - "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", - "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" + "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", + "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.28.1" - }, - "identify": { - "hashes": [ - "sha256:285a7d27e397652e8cafe537a6cc97dd470a970f48fb2e9d979aa38eae5513ac", - "sha256:993b0f01b97e0568c179bb9196391ff391bfb88a99099dbf5ce392b68f42d0af" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==2.6.4" + "version": "==0.27.2" }, "idna": { "hashes": [ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "index": "pypi", "markers": "python_version >= '3.6'", "version": "==3.10" }, - "jsonschema": { + "isort": { "hashes": [ - "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", - "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" + "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", + "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==4.23.0" + "markers": "python_full_version >= '3.8.0'", + "version": "==5.13.2" }, - "jsonschema-spec": { + "jinja2": { "hashes": [ - "sha256:873e396ad1ba6edf9f52d6174c110d4fafb7b5f5894744246a53fe75e5251ec2", - "sha256:e6dcf7056734ec6854f7888da6c08ce6c421f28aeeddce96bb90de0fb6d711ef" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "index": "pypi", - "markers": "python_full_version >= '3.8.0' and python_full_version < '4.0.0'", - "version": "==0.2.4" + "markers": "python_version >= '3.7'", + "version": "==3.1.4" }, - "jsonschema-specifications": { + "markdown-it-py": { "hashes": [ - "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1", - "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb" + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" ], - "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2023.7.1" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56", - "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4", - "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8", - "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282", - "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757", - "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424", - "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b", - "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255", - "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70", - "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94", - "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074", - "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c", - "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee", - "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9", - "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9", - "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69", - "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f", - "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3", - "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9", - "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d", - "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977", - "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b", - "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43", - "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658", - "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a", - "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd", - "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83", - "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4", - "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696", - "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05", - "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3", - "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6", - "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895", - "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4", - "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba", - "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03", - "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c" + "version": "==3.0.0" + }, + "markupsafe": { + "hashes": [ + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.10.0" + "markers": "python_version >= '3.9'", + "version": "==3.0.2" + }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.1.2" }, "mypy-extensions": { "hashes": [ "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" ], - "index": "pypi", "markers": "python_version >= '3.5'", "version": "==1.0.0" }, - "nodeenv": { + "openapi-python-client": { "hashes": [ - "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", - "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" + "sha256:b0ef2398c6b7f754f5a177ed9db77dfc244562cd1c62e6abb4cb10571e417f76", + "sha256:f2eb66b207bfcb8ef195ebe90bef90a8c0ec40a49ee7ad5cc71c0c45ea736ead" ], "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==1.9.1" + "markers": "python_version >= '3.9' and python_version < '4.0'", + "version": "==0.22.0" }, "packaging": { "hashes": [ "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], - "index": "pypi", "markers": "python_version >= '3.8'", "version": "==24.2" }, - "pathable": { - "hashes": [ - "sha256:5c869d315be50776cc8a993f3af43e0c60dc01506b399643f919034ebf4cdcab", - "sha256:cdd7b1f9d7d5c8b8d3315dbf5a86b2596053ae845f056f57d97c0eefff84da14" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.0' and python_full_version < '4.0.0'", - "version": "==0.4.3" - }, "pathspec": { "hashes": [ "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" ], - "index": "pypi", "markers": "python_version >= '3.8'", "version": "==0.12.1" }, @@ -408,28 +366,9 @@ "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], - "index": "pypi", "markers": "python_version >= '3.8'", "version": "==4.3.6" }, - "prance": { - "hashes": [ - "sha256:6a4276fa07ed9f22feda4331097d7503c4adc3097e46ffae97425f2c1026bd9f", - "sha256:d8c15f8ac34019751cc4945f866d8d964d7888016d10de3592e339567177cabe" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==23.6.21.0" - }, - "pre-commit": { - "hashes": [ - "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", - "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==3.8.0" - }, "pydantic": { "hashes": [ "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", @@ -546,6 +485,22 @@ "markers": "python_version >= '3.8'", "version": "==2.27.2" }, + "pygments": { + "hashes": [ + "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", + "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" + ], + "markers": "python_version >= '3.8'", + "version": "==2.19.1" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.9.0.post0" + }, "python-dotenv": { "hashes": [ "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", @@ -615,15 +570,6 @@ "markers": "python_version >= '3.8'", "version": "==6.0.2" }, - "referencing": { - "hashes": [ - "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf", - "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==0.30.2" - }, "requests": { "hashes": [ "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", @@ -633,132 +579,21 @@ "markers": "python_version >= '3.8'", "version": "==2.32.3" }, - "rfc3339-validator": { + "rich": { "hashes": [ - "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", - "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa" + "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", + "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.1.4" - }, - "rpds-py": { - "hashes": [ - "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", - "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", - "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", - "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", - "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9", - "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543", - "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", - "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", - "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d", - "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", - "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", - "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", - "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", - "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", - "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99", - "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", - "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd", - "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe", - "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", - "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", - "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f", - "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3", - "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca", - "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d", - "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e", - "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", - "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea", - "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", - "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", - "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", - "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff", - "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723", - "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e", - "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493", - "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6", - "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", - "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091", - "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", - "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", - "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", - "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728", - "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", - "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c", - "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", - "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7", - "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", - "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", - "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967", - "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", - "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24", - "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055", - "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d", - "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", - "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e", - "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", - "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", - "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", - "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", - "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652", - "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8", - "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11", - "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", - "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96", - "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", - "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b", - "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e", - "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c", - "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9", - "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec", - "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", - "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37", - "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad", - "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", - "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c", - "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf", - "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", - "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", - "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d", - "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09", - "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", - "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566", - "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", - "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338", - "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", - "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c", - "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", - "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", - "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3", - "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123", - "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520", - "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831", - "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", - "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", - "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", - "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", - "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", - "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", - "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", - "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", - "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", - "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d", - "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00", - "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==0.22.3" + "markers": "python_full_version >= '3.8.0'", + "version": "==13.9.4" }, "ruamel.yaml": { "hashes": [ - "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58", - "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1" + "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636", + "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b" ], "markers": "python_version >= '3.7'", - "version": "==0.18.10" + "version": "==0.18.6" }, "ruamel.yaml.clib": { "hashes": [ @@ -814,35 +649,41 @@ }, "ruff": { "hashes": [ - "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37", - "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35", - "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c", - "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7", - "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a", - "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8", - "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99", - "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd", - "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565", - "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad", - "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378", - "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca", - "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250", - "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4", - "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9", - "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112", - "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89", - "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307" + "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", + "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", + "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", + "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", + "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", + "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", + "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1", + "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", + "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", + "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162", + "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", + "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", + "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", + "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", + "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", + "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764", + "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807", + "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905" + ], + "markers": "python_version >= '3.7'", + "version": "==0.8.6" + }, + "shellingham": { + "hashes": [ + "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", + "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" ], - "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.7.1" + "version": "==1.5.4" }, "six": { "hashes": [ "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" ], - "index": "pypi", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.17.0" }, @@ -851,48 +692,16 @@ "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" ], - "index": "pypi", "markers": "python_version >= '3.7'", "version": "==1.3.1" }, - "tomli": { - "hashes": [ - "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", - "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", - "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", - "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", - "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", - "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", - "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", - "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", - "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", - "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", - "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", - "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", - "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", - "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", - "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", - "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", - "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", - "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", - "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", - "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", - "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", - "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", - "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", - "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", - "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", - "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", - "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", - "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", - "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", - "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", - "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", - "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" + "typer": { + "hashes": [ + "sha256:5b59580fd925e89463a29d363e0a43245ec02765bde9fb77d39e5d0f29dd7157", + "sha256:9d444cb96cc268ce6f8b94e13b4335084cef4c079998a9f4851a90229a3bd25c" ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "markers": "python_version >= '3.7'", + "version": "==0.13.1" }, "typing-extensions": { "hashes": [ @@ -908,18 +717,8 @@ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "index": "pypi", "markers": "python_version >= '3.9'", "version": "==2.3.0" - }, - "virtualenv": { - "hashes": [ - "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb", - "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==20.28.1" } }, "develop": {} diff --git a/src/builder/README.md b/src/builder/README.md index c9a3b53..392f432 100644 --- a/src/builder/README.md +++ b/src/builder/README.md @@ -11,7 +11,7 @@ 2. **Создание зависимостей для работы сборки библиотеки:** ```bash - pip install requirements_builder.txt + pip install -r requirements_builder.txt ``` 3. **Создание зависимостей для библиотеки:** @@ -32,8 +32,7 @@ ``` 5. **Установка бибилотеки с сериса TestPyPI:** - - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator1 - - pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator2 + - pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ pachca-generator==0.1.1 ## 📂 Структура генератора @@ -54,5 +53,5 @@ _src/builder/_ #### 🛠️ Makefile - файл с инструкциями для утилиты make, которая нужна для автоматической сборки проекта. -#### 📦 setup_generator1.py, setup_generator2.py +#### 📦 setup.py - файл с описанием, каким именно образом будет упакован код для медотов генерации \ No newline at end of file diff --git a/src/builder/requirements.txt b/src/builder/requirements.txt index fa5fa4b..8e512c7 100644 --- a/src/builder/requirements.txt +++ b/src/builder/requirements.txt @@ -1,55 +1,17 @@ -annotated-types==0.7.0 anyio==4.7.0 attrs==24.3.0 -black==24.10.0 -certifi==2024.12.14 -cfgv==3.4.0 -chardet==5.2.0 -charset-normalizer==3.4.1 -click==8.1.8 -colorama==0.4.6 -distlib==0.3.9 -exceptiongroup==1.2.2 -filelock==3.16.1 -h11==0.14.0 httpcore==1.0.7 -httpx==0.28.1 -identify==2.6.4 -idna==3.10 -jsonschema==4.23.0 -jsonschema-spec==0.2.4 -jsonschema-specifications==2023.7.1 -lazy-object-proxy==1.10.0 -mypy-extensions==1.0.0 -nodeenv==1.9.1 -packaging==24.2 -pathable==0.4.3 -pathspec==0.12.1 -platformdirs==4.3.6 -prance==23.6.21.0 -pre-commit==3.8.0 -pydantic==2.10.4 -Jinja2==3.1.5 -pydantic_core==2.27.2 +httpx==0.27.2 +Jinja2==3.1.4 +openapi-python-client==0.22.0 python-dotenv==1.0.1 PyYAML==6.0.2 -referencing==0.30.2 -requests==2.32.3 -rfc3339-validator==0.1.4 -rpds-py==0.22.3 -ruff==0.7.1 -six==1.17.0 -sniffio==1.3.1 -tomli==2.2.1 +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.12 typing_extensions==4.12.2 -urllib3==2.3.0 -MarkupSafe==3.0.2 -Pygments==2.19.0 -markdown-it-py==3.0.0 -mdurl==0.1.2 -python-dateutil==2.9.0.post0 -rich==13.9.4 -ruff==0.8.6 -shellingham==1.5.4 -typer==0.15.1 -virtualenv==20.28.1 +black==24.10.0 +isort==5.13.2 +pydantic==2.10.4 +pydantic_core==2.27.2 +requests==2.32.3 +python-dotenv==1.0.1 \ No newline at end of file diff --git a/src/builder/setup_generator1.py b/src/builder/setup.py similarity index 61% rename from src/builder/setup_generator1.py rename to src/builder/setup.py index 5c559e0..7d34875 100644 --- a/src/builder/setup_generator1.py +++ b/src/builder/setup.py @@ -1,10 +1,9 @@ -from setuptools import setup, find_packages - import json import os -from dotenv import load_dotenv from pathlib import Path +from dotenv import load_dotenv +from setuptools import find_packages, setup PACKAGE_VERSION = 'Версия из YAML' @@ -26,18 +25,23 @@ def read_pipenv_dependencies(fname): if __name__ == '__main__': setup( - name='pachca_generator1', + name='PachcaAPI', long_description=long_description, long_description_content_type='text/markdown', version=os.getenv('PACKAGE_VERSION', PACKAGE_VERSION), - package_dir={'': '../generator1/pachca-api-open-api-3-0-client'}, - packages=find_packages( - '../generator1/pachca-api-open-api-3-0-client', include=[ - 'pachca_api_open_api_3_0_client*'] - ), + package_dir={'': '..'}, + packages=find_packages('..', include=[ + 'generator1*']), + include_package_data=True, description='A pachca_api package generator1.', install_requires=[ - *read_pipenv_dependencies('Pipfile.lock'), + *read_pipenv_dependencies('Pipfile.lock'), ], - python_version='>=3.11' + entry_points={ + 'console_scripts': [ + 'run_generate_and_test=generator1.api_generator:gen_and_test', + 'run_generator=generator1.api_generator:ganerate', + 'run_test=generator1.api_generator:test', + ], + }, ) diff --git a/src/builder/setup_generator2.py b/src/builder/setup_generator2.py deleted file mode 100644 index eef0ecc..0000000 --- a/src/builder/setup_generator2.py +++ /dev/null @@ -1,43 +0,0 @@ -from setuptools import setup, find_packages - -import json -import os -from dotenv import load_dotenv -from pathlib import Path - - -PACKAGE_VERSION = 'Версия из YAML' - -load_dotenv() - -this_directory = Path(__file__).parent -long_description = ( - this_directory / "../../README.md" -).read_text(encoding='utf-8') - - -def read_pipenv_dependencies(fname): - """Получаем из Pipfile.lock зависимости по умолчанию.""" - filepath = os.path.join(os.path.dirname(__file__), fname) - with open(filepath) as lockfile: - lockjson = json.load(lockfile) - return [dependency for dependency in lockjson.get('default')] - - -if __name__ == '__main__': - setup( - name='pachca_generator2', - long_description=long_description, - long_description_content_type='text/markdown', - version=os.getenv('PACKAGE_VERSION', PACKAGE_VERSION), - package_dir={'': '../generator2'}, - packages=find_packages( - '../generator2', include=[ - 'generator2_full*'] - ), - description='A pachca_api package generator2.', - install_requires=[ - *read_pipenv_dependencies('Pipfile.lock'), - ], - python_version='>=3.11' - ) diff --git a/src/generator1/__init__.py b/src/generator1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/api_generator.py b/src/generator1/api_generator.py new file mode 100644 index 0000000..4463cb4 --- /dev/null +++ b/src/generator1/api_generator.py @@ -0,0 +1,32 @@ +import os +import subprocess +import sys + +from generator1.generator import INSTALL_PATH + +generator_script_path = os.path.join(INSTALL_PATH, "generator.py") + + +def generate(): + command = [sys.executable, generator_script_path, "generate"] + result = subprocess.run(command, check=True, shell=True, text=True) + + if result.returncode == 0: + print("Команда выполнена успешно.") + else: + print("Ошибка выполнения команды:", result.returncode) + + +def test(): + command = [sys.executable, generator_script_path, "test"] + result = subprocess.run(command, check=True, shell=True, text=True) + + if result.returncode == 0: + print("Команда выполнена успешно.") + else: + print("Ошибка выполнения команды:", result.returncode) + + +def gen_and_test(): + generate() + test() diff --git a/src/generator1/generator.py b/src/generator1/generator.py index bdf2200..1072303 100644 --- a/src/generator1/generator.py +++ b/src/generator1/generator.py @@ -1,17 +1,18 @@ +import os import os.path +import site import subprocess import sys -import os -import requests +import requests +INSTALL_PATH = os.path.join(site.getsitepackages()[1], "generator1") +# INSTALL_PATH = ".generator1" MIN_ARGS = 2 COMMAND_INDEX = 1 GENERATE_COMMAND = "generate" INSTALL_TEST_COMMAND = "test" -DEFAULT_YAML_URL = ( - "https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml" -) +DEFAULT_YAML_URL = "https://raw.githubusercontent.com/pachca/openapi/main/openapi.yaml" BASE_DIR = os.path.dirname(os.path.abspath(__file__)) OPENAPI_FILE_PATH = os.path.join(BASE_DIR, "openapi.yaml") @@ -22,11 +23,7 @@ def run_command(command): subprocess.run(command, check=True, shell=True, text=True) print(f"Команда выполнена: {command}") except subprocess.CalledProcessError as e: - print( - f"Ошибка при выполнении команды: {command}\n" - f"Код ошибки: {e.returncode}\n" - f"Вывод:\n{e.stderr}" - ) + print(f"Ошибка при выполнении команды: {command}\nКод ошибки: {e.returncode}\nВывод:\n{e.stderr}") def download_yaml(url): @@ -48,27 +45,30 @@ def generate_client(yaml_url): """Генерация клиента и запуск скрипта-генератора.""" download_yaml(yaml_url) print("Генерация клиента...") - run_command( + openapi_python_client = ( f"openapi-python-client generate --path {OPENAPI_FILE_PATH} " - f"--custom-template-path=./templates --overwrite" + f"--custom-template-path={INSTALL_PATH}/templates --overwrite " + f"--output-path {INSTALL_PATH}" ) - run_command("python pydantic_script.py") - run_command("python script.py") + run_command(openapi_python_client) + + pydantic_script_path = os.path.join(INSTALL_PATH, "pydantic_script.py") + script_path = os.path.join(INSTALL_PATH, "script.py") + run_command([sys.executable, pydantic_script_path]) + run_command([sys.executable, script_path]) def install_and_run_tests(): """Установка пакета и запуск тест-запросов.""" + pachca_path = os.path.join(INSTALL_PATH, "pachca.py") print("Установка пакета и запуск тест-запросов...") - run_command("pip install ./pachca-api-open-api-3-0-client") - run_command("python pachca.py") + run_command(f"pip install {INSTALL_PATH}") + run_command([sys.executable, pachca_path]) if __name__ == "__main__": if len(sys.argv) < MIN_ARGS: - print( - "Пример команды: python generator.py [generate|test] " - "[--url <ссылка на .yaml>]" - ) + print("Пример команды: python generator.py [generate|test] [--url <ссылка на .yaml>]") sys.exit(COMMAND_INDEX) command = sys.argv[COMMAND_INDEX] @@ -87,8 +87,5 @@ def install_and_run_tests(): if command in commands: commands[command]() else: - print( - "Некорректный аргумент. Введите 'generate' для генерации клиента " - "или 'test' для запуска тестов." - ) + print("Некорректный аргумент. Введите 'generate' для генерации клиента или 'test' для запуска тестов.") sys.exit(COMMAND_INDEX) diff --git a/src/generator1/pachca.py b/src/generator1/pachca.py index 63d4b26..a497cad 100644 --- a/src/generator1/pachca.py +++ b/src/generator1/pachca.py @@ -3,32 +3,23 @@ import os from dotenv import load_dotenv -from logger_setup import setup_logging from pachca_api_open_api_3_0_client.client import Pachca -from pachca_api_open_api_3_0_client.models import ( - CreateTaskBodyTask, - EditMessageBody, - EditMessages, - GroupTag, - MembersChat, - QueryStatusStatus, -) +from pachca_api_open_api_3_0_client.logger_setup import setup_logging +from pachca_api_open_api_3_0_client.models import (CreateTaskBodyTask, + EditMessageBody, + EditMessages, GroupTag, + MembersChat, + QueryStatusStatus) from pachca_api_open_api_3_0_client.models.base_chat import BaseChat -from pachca_api_open_api_3_0_client.models.code_reaction import ( - CodeReaction, -) -from pachca_api_open_api_3_0_client.models.create_chat_body import ( - CreateChatBody, -) -from pachca_api_open_api_3_0_client.models.create_message_body import ( - CreateMessageBody, -) -from pachca_api_open_api_3_0_client.models.create_messages import ( - CreateMessages, -) -from pachca_api_open_api_3_0_client.models.create_task_body import ( - CreateTaskBody, -) +from pachca_api_open_api_3_0_client.models.code_reaction import CodeReaction +from pachca_api_open_api_3_0_client.models.create_chat_body import \ + CreateChatBody +from pachca_api_open_api_3_0_client.models.create_message_body import \ + CreateMessageBody +from pachca_api_open_api_3_0_client.models.create_messages import \ + CreateMessages +from pachca_api_open_api_3_0_client.models.create_task_body import \ + CreateTaskBody load_dotenv() pachca = Pachca(os.getenv('TOKEN')) diff --git a/src/generator1/pydantic_script.py b/src/generator1/pydantic_script.py index 74118be..e9653bc 100644 --- a/src/generator1/pydantic_script.py +++ b/src/generator1/pydantic_script.py @@ -1,8 +1,10 @@ import os +from generator1.generator import INSTALL_PATH + def correcting_imports_in_model_files(file_path): - with open(file_path, 'r', encoding='utf-8') as file: + with open(file_path, encoding="utf-8") as file: content = file.readlines() new_content = [] @@ -10,7 +12,7 @@ def correcting_imports_in_model_files(file_path): for line in content: # Проверяем, является ли строка условием TYPE_CHECKING - if line.strip() == 'if TYPE_CHECKING:': + if line.strip() == "if TYPE_CHECKING:": skip_next_lines = True continue # Пропускаем эту строку @@ -22,22 +24,18 @@ def correcting_imports_in_model_files(file_path): new_content.append(line) # Добавляем строку как есть # Если встретили пустую строку, значит закончили с импортами - if line.strip() == '': + if line.strip() == "": skip_next_lines = False # Записываем изменения обратно в файл - with open(file_path, 'w', encoding='utf-8') as file: + with open(file_path, "w", encoding="utf-8") as file: file.writelines(new_content) def changes_all_model_files(directory): for filename in os.listdir(directory): - if filename.endswith('.py'): - correcting_imports_in_model_files( - os.path.join(directory, filename) - ) + if filename.endswith(".py"): + correcting_imports_in_model_files(os.path.join(directory, filename)) -changes_all_model_files( - './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/models/', -) +changes_all_model_files(os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\models")) diff --git a/src/generator1/script.py b/src/generator1/script.py index 5363f20..dc9d372 100644 --- a/src/generator1/script.py +++ b/src/generator1/script.py @@ -6,9 +6,11 @@ import yaml from jinja2 import Environment, FileSystemLoader +from generator1.generator import INSTALL_PATH + def extract_functions_and_imports_from_file(file_path) -> None: - with open(file_path, 'r', encoding='utf-8') as file: + with open(file_path, encoding="utf-8") as file: tree = ast.parse(file.read()) functions = [] @@ -21,18 +23,18 @@ def extract_functions_and_imports_from_file(file_path) -> None: ): functions.append(ast.unparse(node)) elif isinstance(node, ast.ImportFrom): - module = node.module if node.module else '.' + module = node.module if node.module else "." for alias in node.names: - if module == 'typing': - imports.append(f'from typing import {alias.name}') - elif module.startswith('models'): - imports.append(f'from .models import {alias.name}') - elif module == 'types': - imports.append(f'from .types import {alias.name}') - elif module == 'client_serv': - imports.append(f'from .client_serv import {alias.name}') + if module == "typing": + imports.append(f"from typing import {alias.name}") + elif module.startswith("models"): + imports.append(f"from .models import {alias.name}") + elif module == "types": + imports.append(f"from .types import {alias.name}") + elif module == "client_serv": + imports.append(f"from .client_serv import {alias.name}") else: - imports.append(f'from {module} import {alias.name}') + imports.append(f"from {module} import {alias.name}") return functions, imports @@ -42,7 +44,7 @@ def get_all_api_functions_and_imports(api_dir): all_imports = [] for root, _, files in os.walk(api_dir): for file in files: - if file.endswith('.py'): + if file.endswith(".py"): file_path = os.path.join(root, file) functions, imports = extract_functions_and_imports_from_file( file_path, @@ -53,34 +55,31 @@ def get_all_api_functions_and_imports(api_dir): def get_base_url_from_yaml(openapi_yaml): - with open(openapi_yaml, 'r', encoding='utf-8') as file: + with open(os.path.join(INSTALL_PATH, openapi_yaml), encoding="utf-8") as file: data = yaml.safe_load(file) - return data['servers'][0]['url'] + return data["servers"][0]["url"] -api_dir = './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/api' -openapi_yaml = 'openapi.yaml' +api_dir = os.path.join(INSTALL_PATH, r"pachca_api_open_api_3_0_client\api") +openapi_yaml = "openapi.yaml" endpoints, imports = get_all_api_functions_and_imports(api_dir) base_url = get_base_url_from_yaml(openapi_yaml) - env = Environment( - loader=FileSystemLoader('templates'), + loader=FileSystemLoader(os.path.join(INSTALL_PATH, "templates")), ) -client_template = env.get_template('client.py.jinja') +client_template = env.get_template("client.py.jinja") -client_path = ( - './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/client.py' -) +client_path = os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client.py") -with open(client_path, mode='w', encoding='utf-8') as file: +with open(client_path, mode="w", encoding="utf-8") as file: unique_imports = list(set(imports)) models_imports = sorted( [ model for model in unique_imports if model.startswith( - 'from .models', + "from .models", ) ], ) @@ -89,7 +88,7 @@ def get_base_url_from_yaml(openapi_yaml): model for model in unique_imports if model.startswith( - 'from typing import', + "from typing import", ) ], ) @@ -98,103 +97,81 @@ def get_base_url_from_yaml(openapi_yaml): model for model in unique_imports if model.startswith( - 'from .types import', + "from .types import", ) ], ) other_imports = sorted( list( - set(unique_imports) - - set(typing_imports) - - set(types_imports) - - set(models_imports), + set(unique_imports) - set(typing_imports) - set(types_imports) - set(models_imports), ), ) if models_imports: models_imports_str = ( - 'from .models import (\n ' - + ',\n '.join( - [ - model.split('from .models import ')[-1] - for model in models_imports - ], + "from .models import (\n " + + ",\n ".join( + [model.split("from .models import ")[-1] for model in models_imports], ) - + '\n)' + + "\n)" ) - file.write(models_imports_str + '\n\n') + file.write(models_imports_str + "\n\n") if typing_imports: typing_imports_str = ( - 'from typing import (\n ' - + ',\n '.join( - [ - model.split('from typing import ')[-1] - for model in typing_imports - ], + "from typing import (\n " + + ",\n ".join( + [model.split("from typing import ")[-1] for model in typing_imports], ) - + '\n)' + + "\n)" ) - file.write(typing_imports_str + '\n\n') + file.write(typing_imports_str + "\n\n") if types_imports: types_imports_str = ( - 'from .types import (\n ' - + ',\n '.join( - [ - model.split('from .types import ')[-1] - for model in types_imports - ], + "from .types import (\n " + + ",\n ".join( + [model.split("from .types import ")[-1] for model in types_imports], ) - + '\n)' + + "\n)" ) - file.write(types_imports_str + '\n\n') + file.write(types_imports_str + "\n\n") if other_imports: - file.write('\n'.join(other_imports) + '\n\n') + file.write("\n".join(other_imports) + "\n\n") file.write(client_template.render(endpoints=endpoints, base_url=base_url)) -cli_servis_path = ( - './pachca-api-open-api-3-0-client/' - 'pachca_api_open_api_3_0_client/' - 'client_serv.py' -) +cli_servis_path = os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client_serv.py") -logger_setup_path = ( - './pachca-api-open-api-3-0-client/' - 'pachca_api_open_api_3_0_client/' - 'logger_setup.py' -) +logger_setup_path = os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\logger_setup.py") source_file_serv = os.path.join( os.path.dirname(__file__), - '..', - 'generator1', - 'client_servis.py', + "..", + "generator1", + "client_servis.py", ) shutil.copy(source_file_serv, cli_servis_path) source_file_log = os.path.join( os.path.dirname(__file__), - '..', - 'generator1', - 'logger_setup.py', + "..", + "generator1", + "logger_setup.py", ) shutil.copy(source_file_log, logger_setup_path) try: subprocess.run( [ - 'black', - './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/' - 'client.py', - '--line-length', - '79', + "black", + os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client.py"), + "--line-length", + "79", ], check=True, ) subprocess.run( [ - 'isort', - './pachca-api-open-api-3-0-client/pachca_api_open_api_3_0_client/' - 'client.py', + "isort", + os.path.join(INSTALL_PATH, "pachca_api_open_api_3_0_client\client.py"), ], ) except subprocess.CalledProcessError as e: - print('Автолинтер не сработал!', e) + print("Автолинтер не сработал!", e) diff --git a/src/generator1/templates/__init__.py b/src/generator1/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator1/templates/macros/__init__.py b/src/generator1/templates/macros/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/generator2/generate_pydantic_model.py b/src/generator2/generate_pydantic_model.py index effd926..4a63c7a 100644 --- a/src/generator2/generate_pydantic_model.py +++ b/src/generator2/generate_pydantic_model.py @@ -1,9 +1,6 @@ +from .schema_link_processor import load_schema, new_replace_ref_with_schema from .services.constants import ENUM_TYPES, PYTHON_TYPES from .services.file_writer import write_to_file -from .schema_link_processor import ( - load_schema, - new_replace_ref_with_schema, -) def check_error_field(model_name: str, field_name: str, field_type: str): diff --git a/src/generator2/generator2_full/logger_setup.py b/src/generator2/generator2_full/logger_setup.py index bf6f28d..5626a8f 100644 --- a/src/generator2/generator2_full/logger_setup.py +++ b/src/generator2/generator2_full/logger_setup.py @@ -1,10 +1,11 @@ import logging -from logging.handlers import RotatingFileHandler import os +from logging.handlers import RotatingFileHandler from pathlib import Path from .constants import BACKUP_COUNT, LOG_FILE_NAME, MAX_FILE_SIZE + def setup_logging(logger_name: str) -> logging.Logger: logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) diff --git a/src/generator2/request_methods_generator.py b/src/generator2/request_methods_generator.py index 096ce6e..586593f 100644 --- a/src/generator2/request_methods_generator.py +++ b/src/generator2/request_methods_generator.py @@ -14,8 +14,9 @@ PARAM_NAME_SORT, PARAM_NAME_SORT_FIELD, PARAM_TYPE_KEY, PREFIX_REQUEST, PREFIX_RESPONSE, SCHEMA_SORT_ID, - SPECIFICATION_FILE_NAME, TYPE_SORT_FIELD, - TEMPLATE_CLASS_REQUEST_METHODS) + SPECIFICATION_FILE_NAME, + TEMPLATE_CLASS_REQUEST_METHODS, + TYPE_SORT_FIELD) def format_path_params(param_path: dict[str, Union[str, dict]]) -> str: diff --git a/src/generator2/services/constants.py b/src/generator2/services/constants.py index b1c05be..f0557a5 100644 --- a/src/generator2/services/constants.py +++ b/src/generator2/services/constants.py @@ -1,6 +1,6 @@ import os -from pathlib import Path import sys +from pathlib import Path # PATH_TO_YAML = './openapi_test.yaml' PATH_TO_YAML = ( diff --git a/src/generator2/services/yaml_loader.py b/src/generator2/services/yaml_loader.py index 460c1fd..2fe2d94 100644 --- a/src/generator2/services/yaml_loader.py +++ b/src/generator2/services/yaml_loader.py @@ -4,5 +4,4 @@ from .constants import PATH_TO_YAML - YAML_DICT = YAML(typ='rt').load(Path(PATH_TO_YAML)) diff --git a/src/generator2/yaml_processor.py b/src/generator2/yaml_processor.py index 587d6ab..f1a983f 100644 --- a/src/generator2/yaml_processor.py +++ b/src/generator2/yaml_processor.py @@ -1,14 +1,11 @@ import sys -from .services.file_writer import write_to_file from .generate_pydantic_model import look_into_schema_new -from .services.logger_setup import setup_logging from .schema_link_processor import load_schema +from .services.constants import HTTP_METHODS, PREFIX_REQUEST, PREFIX_RESPONSE +from .services.file_writer import write_to_file +from .services.logger_setup import setup_logging from .services.yaml_loader import YAML_DICT -from .services.constants import ( - HTTP_METHODS, PREFIX_RESPONSE, PREFIX_REQUEST -) - logger = setup_logging('yaml_processor') diff --git a/src/repository/PachcaAPI-0.0.39-py3-none-any.whl b/src/repository/PachcaAPI-0.0.39-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..d68e9ccda28e7af98d11e66b6742be69aa298e7f GIT binary patch literal 22867 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 c@b76~h~TgP1Fo;td;kCd diff --git a/src/repository/pachca_generator2-0.2.3-py3-none-any.whl b/src/repository/pachca_generator2-0.2.3-py3-none-any.whl deleted file mode 100644 index a975b04daca7aaca76cf15c07ca0ed339e4f1334..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137582 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