botix 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- botix/__init__.py +98 -0
- botix/api/__init__.py +11 -0
- botix/api/channels_api.py +279 -0
- botix/api/chats_api.py +663 -0
- botix/api/contacts_api.py +2043 -0
- botix/api/messages_api.py +708 -0
- botix/api/scenarios_api.py +594 -0
- botix/api/system_api.py +291 -0
- botix/api/webhooks_api.py +1369 -0
- botix/api_client.py +805 -0
- botix/api_response.py +21 -0
- botix/client.py +360 -0
- botix/configuration.py +611 -0
- botix/exceptions.py +219 -0
- botix/idempotency.py +56 -0
- botix/models/__init__.py +58 -0
- botix/models/channel.py +103 -0
- botix/models/channels_list200_response.py +105 -0
- botix/models/channels_list200_response_meta.py +89 -0
- botix/models/chat.py +133 -0
- botix/models/chats_list200_response.py +105 -0
- botix/models/contact.py +236 -0
- botix/models/contact_writable.py +128 -0
- botix/models/contacts_add_tag200_response.py +95 -0
- botix/models/contacts_add_tag200_response_data.py +89 -0
- botix/models/contacts_add_tag_request.py +89 -0
- botix/models/contacts_list200_response.py +105 -0
- botix/models/contacts_remove_tag200_response.py +95 -0
- botix/models/error.py +95 -0
- botix/models/error_error.py +103 -0
- botix/models/me_response.py +95 -0
- botix/models/me_response_data.py +107 -0
- botix/models/me_response_data_limits.py +95 -0
- botix/models/me_response_data_rate_limit.py +94 -0
- botix/models/message.py +154 -0
- botix/models/messages_list200_response.py +105 -0
- botix/models/messages_send200_response.py +95 -0
- botix/models/messages_send200_response_data.py +99 -0
- botix/models/messages_send_request.py +103 -0
- botix/models/messages_send_request_attachments_inner.py +93 -0
- botix/models/scenario.py +125 -0
- botix/models/scenarios_list200_response.py +105 -0
- botix/models/scenarios_run200_response.py +95 -0
- botix/models/scenarios_run200_response_data.py +104 -0
- botix/models/scenarios_run_request.py +95 -0
- botix/models/success_contact.py +95 -0
- botix/models/success_with_meta.py +102 -0
- botix/models/success_with_meta_meta.py +93 -0
- botix/models/webhook.py +122 -0
- botix/models/webhook_event.py +48 -0
- botix/models/webhooks_create201_response.py +95 -0
- botix/models/webhooks_create201_response_data.py +95 -0
- botix/models/webhooks_create_request.py +92 -0
- botix/models/webhooks_list200_response.py +99 -0
- botix/models/webhooks_test200_response.py +95 -0
- botix/models/webhooks_test200_response_data.py +113 -0
- botix/models/webhooks_update_request.py +104 -0
- botix/py.typed +0 -0
- botix/rest.py +264 -0
- botix/webhook.py +39 -0
- botix-1.0.0.dist-info/METADATA +187 -0
- botix-1.0.0.dist-info/RECORD +65 -0
- botix-1.0.0.dist-info/WHEEL +5 -0
- botix-1.0.0.dist-info/licenses/LICENSE +21 -0
- botix-1.0.0.dist-info/top_level.txt +1 -0
botix/__init__.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
BOTIX SDK для Python — официальная клиентская библиотека публичного API BOTIX.
|
|
5
|
+
|
|
6
|
+
Точка входа — :class:`botix.Client`. Хелпер :func:`botix.verify_webhook`
|
|
7
|
+
сверяет подпись входящих webhook-сообщений.
|
|
8
|
+
|
|
9
|
+
Пример:
|
|
10
|
+
|
|
11
|
+
import botix
|
|
12
|
+
|
|
13
|
+
client = botix.Client("btx_live_...")
|
|
14
|
+
print(client.me())
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__version__ = "1.0.0"
|
|
18
|
+
|
|
19
|
+
# Высокоуровневое API — то, что использует разработчик в 99% случаев.
|
|
20
|
+
from botix.client import Client as Client
|
|
21
|
+
from botix.idempotency import Response as Response
|
|
22
|
+
from botix.idempotency import generate_idempotency_key as generate_idempotency_key
|
|
23
|
+
from botix.webhook import verify_webhook as verify_webhook
|
|
24
|
+
|
|
25
|
+
# Низкоуровневые компоненты сгенерированного клиента — для опытных пользователей,
|
|
26
|
+
# которым нужен прямой доступ к сырому ApiClient / Configuration / типизированным
|
|
27
|
+
# pydantic-моделям ответов.
|
|
28
|
+
from botix.api.channels_api import ChannelsApi as ChannelsApi
|
|
29
|
+
from botix.api.chats_api import ChatsApi as ChatsApi
|
|
30
|
+
from botix.api.contacts_api import ContactsApi as ContactsApi
|
|
31
|
+
from botix.api.messages_api import MessagesApi as MessagesApi
|
|
32
|
+
from botix.api.scenarios_api import ScenariosApi as ScenariosApi
|
|
33
|
+
from botix.api.system_api import SystemApi as SystemApi
|
|
34
|
+
from botix.api.webhooks_api import WebhooksApi as WebhooksApi
|
|
35
|
+
from botix.api_client import ApiClient as ApiClient
|
|
36
|
+
from botix.api_response import ApiResponse as ApiResponse
|
|
37
|
+
from botix.configuration import Configuration as Configuration
|
|
38
|
+
from botix.exceptions import ApiAttributeError as ApiAttributeError
|
|
39
|
+
from botix.exceptions import ApiException as ApiException
|
|
40
|
+
from botix.exceptions import ApiKeyError as ApiKeyError
|
|
41
|
+
from botix.exceptions import ApiTypeError as ApiTypeError
|
|
42
|
+
from botix.exceptions import ApiValueError as ApiValueError
|
|
43
|
+
from botix.exceptions import OpenApiException as OpenApiException
|
|
44
|
+
|
|
45
|
+
# Типизированные модели данных — для type hints и сериализации.
|
|
46
|
+
from botix.models.channel import Channel as Channel
|
|
47
|
+
from botix.models.chat import Chat as Chat
|
|
48
|
+
from botix.models.contact import Contact as Contact
|
|
49
|
+
from botix.models.contact_writable import ContactWritable as ContactWritable
|
|
50
|
+
from botix.models.error import Error as Error
|
|
51
|
+
from botix.models.error_error import ErrorError as ErrorError
|
|
52
|
+
from botix.models.me_response import MeResponse as MeResponse
|
|
53
|
+
from botix.models.me_response_data import MeResponseData as MeResponseData
|
|
54
|
+
from botix.models.message import Message as Message
|
|
55
|
+
from botix.models.scenario import Scenario as Scenario
|
|
56
|
+
from botix.models.webhook import Webhook as Webhook
|
|
57
|
+
from botix.models.webhook_event import WebhookEvent as WebhookEvent
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"__version__",
|
|
61
|
+
# High-level
|
|
62
|
+
"Client",
|
|
63
|
+
"Response",
|
|
64
|
+
"verify_webhook",
|
|
65
|
+
"generate_idempotency_key",
|
|
66
|
+
# Low-level (advanced) — resource API classes
|
|
67
|
+
"ChannelsApi",
|
|
68
|
+
"ChatsApi",
|
|
69
|
+
"ContactsApi",
|
|
70
|
+
"MessagesApi",
|
|
71
|
+
"ScenariosApi",
|
|
72
|
+
"SystemApi",
|
|
73
|
+
"WebhooksApi",
|
|
74
|
+
# Low-level — core
|
|
75
|
+
"ApiClient",
|
|
76
|
+
"ApiResponse",
|
|
77
|
+
"Configuration",
|
|
78
|
+
# Exceptions
|
|
79
|
+
"ApiException",
|
|
80
|
+
"ApiAttributeError",
|
|
81
|
+
"ApiKeyError",
|
|
82
|
+
"ApiTypeError",
|
|
83
|
+
"ApiValueError",
|
|
84
|
+
"OpenApiException",
|
|
85
|
+
# Models
|
|
86
|
+
"Channel",
|
|
87
|
+
"Chat",
|
|
88
|
+
"Contact",
|
|
89
|
+
"ContactWritable",
|
|
90
|
+
"Error",
|
|
91
|
+
"ErrorError",
|
|
92
|
+
"MeResponse",
|
|
93
|
+
"MeResponseData",
|
|
94
|
+
"Message",
|
|
95
|
+
"Scenario",
|
|
96
|
+
"Webhook",
|
|
97
|
+
"WebhookEvent",
|
|
98
|
+
]
|
botix/api/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
|
|
3
|
+
# import apis into api package
|
|
4
|
+
from botix.api.channels_api import ChannelsApi
|
|
5
|
+
from botix.api.chats_api import ChatsApi
|
|
6
|
+
from botix.api.contacts_api import ContactsApi
|
|
7
|
+
from botix.api.messages_api import MessagesApi
|
|
8
|
+
from botix.api.scenarios_api import ScenariosApi
|
|
9
|
+
from botix.api.system_api import SystemApi
|
|
10
|
+
from botix.api.webhooks_api import WebhooksApi
|
|
11
|
+
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BOTIX Public API
|
|
3
|
+
|
|
4
|
+
Публичный программный интерфейс платформы BOTIX (botix.pro) — позволяет интеграторам и сторонним разработчикам встраивать функционал BOTIX в свои продукты: магазины, CRM, мобильные приложения, бэкенды. **Авторизация:** заголовок `Authorization: Bearer btx_live_…`. Каждый ключ привязан к одному `project_id`. Каждый ключ имеет список `scopes` — операций, которые им разрешены. Без нужного scope — `403 INSUFFICIENT_SCOPE`. **Гейтинг по тарифу:** - тариф без `api_enabled` — `403 API_NOT_AVAILABLE_ON_PLAN` - триальный тариф (`api_write_enabled=0`) — read-only, POST/PUT/PATCH/DELETE → `403 TRIAL_READ_ONLY` - лимиты `api_rate_per_minute` / `api_rate_per_day` — из настроек тарифа (см. ЛК `/billing`) **Стандарт ответов:** обёртка `{success, data, meta}` для успеха и `{success:false, error:{code,message,details}}` для ошибки. **Версионирование:** `/public/v1/*` фиксирован. Новые поля в ответах могут добавляться, удаление/смена типов запрещены.
|
|
5
|
+
|
|
6
|
+
The version of the OpenAPI document: 1.0.0
|
|
7
|
+
Contact: hello@botix.pro
|
|
8
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
9
|
+
|
|
10
|
+
Do not edit the class manually.
|
|
11
|
+
""" # noqa: E501
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import warnings
|
|
15
|
+
from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
|
|
16
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
17
|
+
from typing_extensions import Annotated
|
|
18
|
+
|
|
19
|
+
from botix.models.channels_list200_response import ChannelsList200Response
|
|
20
|
+
|
|
21
|
+
from botix.api_client import ApiClient, RequestSerialized
|
|
22
|
+
from botix.api_response import ApiResponse
|
|
23
|
+
from botix.rest import RESTResponseType
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ChannelsApi:
|
|
27
|
+
"""NOTE: This class is auto generated by OpenAPI Generator
|
|
28
|
+
Ref: https://openapi-generator.tech
|
|
29
|
+
|
|
30
|
+
Do not edit the class manually.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, api_client=None) -> None:
|
|
34
|
+
if api_client is None:
|
|
35
|
+
api_client = ApiClient.get_default()
|
|
36
|
+
self.api_client = api_client
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@validate_call
|
|
40
|
+
def channels_list(
|
|
41
|
+
self,
|
|
42
|
+
_request_timeout: Union[
|
|
43
|
+
None,
|
|
44
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
45
|
+
Tuple[
|
|
46
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
47
|
+
Annotated[StrictFloat, Field(gt=0)]
|
|
48
|
+
]
|
|
49
|
+
] = None,
|
|
50
|
+
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
51
|
+
_content_type: Optional[StrictStr] = None,
|
|
52
|
+
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
53
|
+
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
54
|
+
) -> ChannelsList200Response:
|
|
55
|
+
"""Каналы проекта
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
:param _request_timeout: timeout setting for this request. If one
|
|
59
|
+
number provided, it will be total request
|
|
60
|
+
timeout. It can also be a pair (tuple) of
|
|
61
|
+
(connection, read) timeouts.
|
|
62
|
+
:type _request_timeout: int, tuple(int, int), optional
|
|
63
|
+
:param _request_auth: set to override the auth_settings for an a single
|
|
64
|
+
request; this effectively ignores the
|
|
65
|
+
authentication in the spec for a single request.
|
|
66
|
+
:type _request_auth: dict, optional
|
|
67
|
+
:param _content_type: force content-type for the request.
|
|
68
|
+
:type _content_type: str, Optional
|
|
69
|
+
:param _headers: set to override the headers for a single
|
|
70
|
+
request; this effectively ignores the headers
|
|
71
|
+
in the spec for a single request.
|
|
72
|
+
:type _headers: dict, optional
|
|
73
|
+
:param _host_index: set to override the host_index for a single
|
|
74
|
+
request; this effectively ignores the host_index
|
|
75
|
+
in the spec for a single request.
|
|
76
|
+
:type _host_index: int, optional
|
|
77
|
+
:return: Returns the result object.
|
|
78
|
+
""" # noqa: E501
|
|
79
|
+
|
|
80
|
+
_param = self._channels_list_serialize(
|
|
81
|
+
_request_auth=_request_auth,
|
|
82
|
+
_content_type=_content_type,
|
|
83
|
+
_headers=_headers,
|
|
84
|
+
_host_index=_host_index
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
_response_types_map: Dict[str, Optional[str]] = {
|
|
88
|
+
'200': "ChannelsList200Response",
|
|
89
|
+
}
|
|
90
|
+
response_data = self.api_client.call_api(
|
|
91
|
+
*_param,
|
|
92
|
+
_request_timeout=_request_timeout
|
|
93
|
+
)
|
|
94
|
+
response_data.read()
|
|
95
|
+
return self.api_client.response_deserialize(
|
|
96
|
+
response_data=response_data,
|
|
97
|
+
response_types_map=_response_types_map,
|
|
98
|
+
).data
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@validate_call
|
|
102
|
+
def channels_list_with_http_info(
|
|
103
|
+
self,
|
|
104
|
+
_request_timeout: Union[
|
|
105
|
+
None,
|
|
106
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
107
|
+
Tuple[
|
|
108
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
109
|
+
Annotated[StrictFloat, Field(gt=0)]
|
|
110
|
+
]
|
|
111
|
+
] = None,
|
|
112
|
+
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
113
|
+
_content_type: Optional[StrictStr] = None,
|
|
114
|
+
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
115
|
+
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
116
|
+
) -> ApiResponse[ChannelsList200Response]:
|
|
117
|
+
"""Каналы проекта
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
:param _request_timeout: timeout setting for this request. If one
|
|
121
|
+
number provided, it will be total request
|
|
122
|
+
timeout. It can also be a pair (tuple) of
|
|
123
|
+
(connection, read) timeouts.
|
|
124
|
+
:type _request_timeout: int, tuple(int, int), optional
|
|
125
|
+
:param _request_auth: set to override the auth_settings for an a single
|
|
126
|
+
request; this effectively ignores the
|
|
127
|
+
authentication in the spec for a single request.
|
|
128
|
+
:type _request_auth: dict, optional
|
|
129
|
+
:param _content_type: force content-type for the request.
|
|
130
|
+
:type _content_type: str, Optional
|
|
131
|
+
:param _headers: set to override the headers for a single
|
|
132
|
+
request; this effectively ignores the headers
|
|
133
|
+
in the spec for a single request.
|
|
134
|
+
:type _headers: dict, optional
|
|
135
|
+
:param _host_index: set to override the host_index for a single
|
|
136
|
+
request; this effectively ignores the host_index
|
|
137
|
+
in the spec for a single request.
|
|
138
|
+
:type _host_index: int, optional
|
|
139
|
+
:return: Returns the result object.
|
|
140
|
+
""" # noqa: E501
|
|
141
|
+
|
|
142
|
+
_param = self._channels_list_serialize(
|
|
143
|
+
_request_auth=_request_auth,
|
|
144
|
+
_content_type=_content_type,
|
|
145
|
+
_headers=_headers,
|
|
146
|
+
_host_index=_host_index
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
_response_types_map: Dict[str, Optional[str]] = {
|
|
150
|
+
'200': "ChannelsList200Response",
|
|
151
|
+
}
|
|
152
|
+
response_data = self.api_client.call_api(
|
|
153
|
+
*_param,
|
|
154
|
+
_request_timeout=_request_timeout
|
|
155
|
+
)
|
|
156
|
+
response_data.read()
|
|
157
|
+
return self.api_client.response_deserialize(
|
|
158
|
+
response_data=response_data,
|
|
159
|
+
response_types_map=_response_types_map,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@validate_call
|
|
164
|
+
def channels_list_without_preload_content(
|
|
165
|
+
self,
|
|
166
|
+
_request_timeout: Union[
|
|
167
|
+
None,
|
|
168
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
169
|
+
Tuple[
|
|
170
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
171
|
+
Annotated[StrictFloat, Field(gt=0)]
|
|
172
|
+
]
|
|
173
|
+
] = None,
|
|
174
|
+
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
175
|
+
_content_type: Optional[StrictStr] = None,
|
|
176
|
+
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
177
|
+
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
178
|
+
) -> RESTResponseType:
|
|
179
|
+
"""Каналы проекта
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
:param _request_timeout: timeout setting for this request. If one
|
|
183
|
+
number provided, it will be total request
|
|
184
|
+
timeout. It can also be a pair (tuple) of
|
|
185
|
+
(connection, read) timeouts.
|
|
186
|
+
:type _request_timeout: int, tuple(int, int), optional
|
|
187
|
+
:param _request_auth: set to override the auth_settings for an a single
|
|
188
|
+
request; this effectively ignores the
|
|
189
|
+
authentication in the spec for a single request.
|
|
190
|
+
:type _request_auth: dict, optional
|
|
191
|
+
:param _content_type: force content-type for the request.
|
|
192
|
+
:type _content_type: str, Optional
|
|
193
|
+
:param _headers: set to override the headers for a single
|
|
194
|
+
request; this effectively ignores the headers
|
|
195
|
+
in the spec for a single request.
|
|
196
|
+
:type _headers: dict, optional
|
|
197
|
+
:param _host_index: set to override the host_index for a single
|
|
198
|
+
request; this effectively ignores the host_index
|
|
199
|
+
in the spec for a single request.
|
|
200
|
+
:type _host_index: int, optional
|
|
201
|
+
:return: Returns the result object.
|
|
202
|
+
""" # noqa: E501
|
|
203
|
+
|
|
204
|
+
_param = self._channels_list_serialize(
|
|
205
|
+
_request_auth=_request_auth,
|
|
206
|
+
_content_type=_content_type,
|
|
207
|
+
_headers=_headers,
|
|
208
|
+
_host_index=_host_index
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
_response_types_map: Dict[str, Optional[str]] = {
|
|
212
|
+
'200': "ChannelsList200Response",
|
|
213
|
+
}
|
|
214
|
+
response_data = self.api_client.call_api(
|
|
215
|
+
*_param,
|
|
216
|
+
_request_timeout=_request_timeout
|
|
217
|
+
)
|
|
218
|
+
return response_data.response
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _channels_list_serialize(
|
|
222
|
+
self,
|
|
223
|
+
_request_auth,
|
|
224
|
+
_content_type,
|
|
225
|
+
_headers,
|
|
226
|
+
_host_index,
|
|
227
|
+
) -> RequestSerialized:
|
|
228
|
+
|
|
229
|
+
_host = None
|
|
230
|
+
|
|
231
|
+
_collection_formats: Dict[str, str] = {
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
_path_params: Dict[str, str] = {}
|
|
235
|
+
_query_params: List[Tuple[str, str]] = []
|
|
236
|
+
_header_params: Dict[str, Optional[str]] = _headers or {}
|
|
237
|
+
_form_params: List[Tuple[str, str]] = []
|
|
238
|
+
_files: Dict[
|
|
239
|
+
str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]
|
|
240
|
+
] = {}
|
|
241
|
+
_body_params: Optional[bytes] = None
|
|
242
|
+
|
|
243
|
+
# process the path parameters
|
|
244
|
+
# process the query parameters
|
|
245
|
+
# process the header parameters
|
|
246
|
+
# process the form parameters
|
|
247
|
+
# process the body parameter
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# set the HTTP header `Accept`
|
|
251
|
+
if 'Accept' not in _header_params:
|
|
252
|
+
_header_params['Accept'] = self.api_client.select_header_accept(
|
|
253
|
+
[
|
|
254
|
+
'application/json'
|
|
255
|
+
]
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# authentication setting
|
|
260
|
+
_auth_settings: List[str] = [
|
|
261
|
+
'bearerAuth'
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
return self.api_client.param_serialize(
|
|
265
|
+
method='GET',
|
|
266
|
+
resource_path='/public/v1/channels',
|
|
267
|
+
path_params=_path_params,
|
|
268
|
+
query_params=_query_params,
|
|
269
|
+
header_params=_header_params,
|
|
270
|
+
body=_body_params,
|
|
271
|
+
post_params=_form_params,
|
|
272
|
+
files=_files,
|
|
273
|
+
auth_settings=_auth_settings,
|
|
274
|
+
collection_formats=_collection_formats,
|
|
275
|
+
_host=_host,
|
|
276
|
+
_request_auth=_request_auth
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|