konecty-sdk-python 2.1.7__tar.gz → 2.2.0__tar.gz
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.
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/client.py +12 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/exceptions.py +20 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/auth.py +69 -4
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/PKG-INFO +1 -1
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/pyproject.toml +1 -1
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/.gitignore +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/__init__.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/cli/__init__.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/cli/apply.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/cli/backup.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/cli/pull.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/__init__.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/feature_types/__init__.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/feature_types/cross_module_query.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/feature_types/kpi.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/feature_types/query_json.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/file_manager.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/filters.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/http.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/model.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/serialization.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/__init__.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/admin.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/aggregation.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/base.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/change_user.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/comments.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/export.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/files.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/notifications.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/pat.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/query.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/stream.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/subscriptions.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/settings.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/types.py +0 -0
- {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/README.md +0 -0
|
@@ -463,6 +463,18 @@ class KonectyClient:
|
|
|
463
463
|
fingerprint=fingerprint,
|
|
464
464
|
)
|
|
465
465
|
|
|
466
|
+
async def impersonate(
|
|
467
|
+
self, user_id: Optional[str] = None, code: Optional[int] = None
|
|
468
|
+
) -> Dict[str, Any]:
|
|
469
|
+
"""
|
|
470
|
+
Issue a support session (1 h) for another user (POST /api/auth/impersonate).
|
|
471
|
+
|
|
472
|
+
Exactly one of ``user_id`` or ``code``. Requires an admin first-party session.
|
|
473
|
+
Returns ``{"authId", "expiresAt", "user"}``; the returned authId is not adopted by
|
|
474
|
+
this client. Raises KonectyImpersonateError with a machine-readable ``code``.
|
|
475
|
+
"""
|
|
476
|
+
return await self._auth.impersonate(user_id=user_id, code=code)
|
|
477
|
+
|
|
466
478
|
async def get_login_options(self) -> Dict[str, Any]:
|
|
467
479
|
"""Get login method flags for the namespace (GET /api/auth/login-options)."""
|
|
468
480
|
return await self._auth.get_login_options()
|
|
@@ -31,6 +31,26 @@ class KonectyGoogleSessionError(KonectyAPIError):
|
|
|
31
31
|
self.code = code
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
class KonectyImpersonateError(KonectyAPIError):
|
|
35
|
+
"""
|
|
36
|
+
Raised by impersonate. Carries the machine-readable ``code`` from ``errors[0].code``
|
|
37
|
+
(``IMPERSONATE_FORBIDDEN``, ``IMPERSONATE_INVALID_TARGET``,
|
|
38
|
+
``IMPERSONATE_TARGET_NOT_FOUND``, ``IMPERSONATE_TARGET_NOT_ALLOWED``,
|
|
39
|
+
``IMPERSONATED_SESSION_FORBIDDEN``, ``admin-credential-routes-require-session``);
|
|
40
|
+
``failed`` covers transport errors, unreadable bodies and answers without a recognised
|
|
41
|
+
code, e.g. a plain 401. ``IMPERSONATE_INVALID_TARGET`` is also raised locally, with no
|
|
42
|
+
request, when the target does not have exactly one of ``user_id`` or ``code``.
|
|
43
|
+
|
|
44
|
+
Subclasses KonectyAPIError so existing ``except KonectyAPIError`` keeps working.
|
|
45
|
+
|
|
46
|
+
Mirrors KonectyImpersonateError in the TypeScript SDK — keep both in sync.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, code: str, message: str) -> None:
|
|
50
|
+
super().__init__(message)
|
|
51
|
+
self.code = code
|
|
52
|
+
|
|
53
|
+
|
|
34
54
|
#: Código devolvido pelo Konecty quando a requisição pede ordenação arbitrária
|
|
35
55
|
#: acima do teto de página. Espelha ``SORT_ABOVE_MAX_PAGE_SIZE`` no SDK
|
|
36
56
|
#: TypeScript — manter os dois em sincronia.
|
|
@@ -5,7 +5,11 @@ from urllib.parse import quote, urlencode
|
|
|
5
5
|
|
|
6
6
|
import aiohttp
|
|
7
7
|
|
|
8
|
-
from ..exceptions import
|
|
8
|
+
from ..exceptions import (
|
|
9
|
+
KonectyAPIError,
|
|
10
|
+
KonectyGoogleSessionError,
|
|
11
|
+
KonectyImpersonateError,
|
|
12
|
+
)
|
|
9
13
|
from .base import BaseService
|
|
10
14
|
|
|
11
15
|
GOOGLE_START_PATH = "/api/auth/google/start"
|
|
@@ -16,6 +20,7 @@ _ENCODE_URI_COMPONENT_SAFE = "!*'()"
|
|
|
16
20
|
GOOGLE_SESSION_PATH = "/api/auth/google/session"
|
|
17
21
|
LOGIN_OPTIONS_PATH = "/api/auth/login-options"
|
|
18
22
|
USER_INFO_PATH = "/rest/auth/info"
|
|
23
|
+
IMPERSONATE_PATH = "/api/auth/impersonate"
|
|
19
24
|
|
|
20
25
|
|
|
21
26
|
_GOOGLE_SESSION_ERROR_CODES = (
|
|
@@ -26,7 +31,19 @@ _GOOGLE_SESSION_ERROR_CODES = (
|
|
|
26
31
|
)
|
|
27
32
|
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
_IMPERSONATE_ERROR_CODES = (
|
|
35
|
+
"IMPERSONATE_FORBIDDEN",
|
|
36
|
+
"IMPERSONATE_INVALID_TARGET",
|
|
37
|
+
"IMPERSONATE_TARGET_NOT_FOUND",
|
|
38
|
+
"IMPERSONATE_TARGET_NOT_ALLOWED",
|
|
39
|
+
"IMPERSONATED_SESSION_FORBIDDEN",
|
|
40
|
+
"admin-credential-routes-require-session",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _first_error_code(
|
|
45
|
+
error: KonectyAPIError, recognised: tuple = _GOOGLE_SESSION_ERROR_CODES
|
|
46
|
+
) -> str:
|
|
30
47
|
"""
|
|
31
48
|
Extract the first recognised ``errors[].code``; ``failed`` when there is none.
|
|
32
49
|
|
|
@@ -36,7 +53,7 @@ def _first_error_code(error: KonectyAPIError) -> str:
|
|
|
36
53
|
errors = error.args[0] if error.args else None
|
|
37
54
|
if isinstance(errors, list):
|
|
38
55
|
for item in errors:
|
|
39
|
-
if isinstance(item, dict) and item.get("code") in
|
|
56
|
+
if isinstance(item, dict) and item.get("code") in recognised:
|
|
40
57
|
return str(item["code"])
|
|
41
58
|
return "failed"
|
|
42
59
|
|
|
@@ -131,6 +148,52 @@ class AuthService(BaseService):
|
|
|
131
148
|
self._client.set_auth_id(auth_id)
|
|
132
149
|
return response
|
|
133
150
|
|
|
151
|
+
async def impersonate(
|
|
152
|
+
self, user_id: Optional[str] = None, code: Optional[int] = None
|
|
153
|
+
) -> Dict[str, Any]:
|
|
154
|
+
"""
|
|
155
|
+
POST /api/auth/impersonate. Issues a support session (1 h) for another user.
|
|
156
|
+
|
|
157
|
+
Pass exactly one of ``user_id`` (the user's ``_id``, sent as ``userId``) or ``code``
|
|
158
|
+
(the user's numeric code). The caller must be an admin authenticated with a
|
|
159
|
+
first-party session. Returns ``{"authId", "expiresAt", "user"}`` (``expiresAt`` is
|
|
160
|
+
ISO 8601). The returned ``authId`` is NOT adopted by this client — the admin session
|
|
161
|
+
stays intact.
|
|
162
|
+
|
|
163
|
+
Raises KonectyImpersonateError — errors[0].message as the message plus the
|
|
164
|
+
machine-readable ``code`` — on any failure. Zero or two targets raise
|
|
165
|
+
``IMPERSONATE_INVALID_TARGET`` without sending a request. The error subclasses
|
|
166
|
+
KonectyAPIError, so callers catching that keep working.
|
|
167
|
+
"""
|
|
168
|
+
if (user_id is not None) == (code is not None):
|
|
169
|
+
raise KonectyImpersonateError(
|
|
170
|
+
"IMPERSONATE_INVALID_TARGET", "Pass exactly one of userId or code"
|
|
171
|
+
)
|
|
172
|
+
payload: Dict[str, Any] = (
|
|
173
|
+
{"userId": user_id} if user_id is not None else {"code": code}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
response = await self._post(IMPERSONATE_PATH, json=payload)
|
|
178
|
+
except KonectyAPIError as error:
|
|
179
|
+
raise KonectyImpersonateError(
|
|
180
|
+
_first_error_code(error, _IMPERSONATE_ERROR_CODES),
|
|
181
|
+
_first_error_message(error),
|
|
182
|
+
) from error
|
|
183
|
+
|
|
184
|
+
data = response.get("data") if isinstance(response, dict) else None
|
|
185
|
+
auth_id = data.get("authId") if isinstance(data, dict) else None
|
|
186
|
+
if not isinstance(auth_id, str) or not auth_id:
|
|
187
|
+
raise KonectyImpersonateError(
|
|
188
|
+
"failed", "Impersonate response has no authId"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
"authId": auth_id,
|
|
193
|
+
"expiresAt": data.get("expiresAt"),
|
|
194
|
+
"user": data.get("user"),
|
|
195
|
+
}
|
|
196
|
+
|
|
134
197
|
async def get_login_options(self) -> Dict[str, Any]:
|
|
135
198
|
"""GET /api/auth/login-options. Flags: passwordEnabled, emailOtpEnabled,
|
|
136
199
|
whatsAppOtpEnabled, webauthnEnabled, webauthnRequired, googleEnabled."""
|
|
@@ -142,7 +205,9 @@ class AuthService(BaseService):
|
|
|
142
205
|
|
|
143
206
|
``user`` carries ``_id``, ``name``, ``email``, ``login``, ``group``, ``role``, ``access``,
|
|
144
207
|
``locale``, ``namespace`` and ``redirectURL`` — the page to open the interface on, or
|
|
145
|
-
None when the user record sets none.
|
|
208
|
+
None when the user record sets none. In a support session (see ``impersonate``) it also
|
|
209
|
+
carries ``impersonatedBy`` (``{"_id", "name"}`` of the admin) and ``impersonationExpiresAt``
|
|
210
|
+
(ISO 8601). Keys are the wire names, as in the TypeScript SDK.
|
|
146
211
|
|
|
147
212
|
Same contract as ``KonectyClient.info()`` in the TypeScript SDK: without a token there is
|
|
148
213
|
no session to ask about, so no request goes out; a 4xx/5xx answer means not logged. Both
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/feature_types/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/feature_types/kpi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/__init__.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/admin.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/aggregation.py
RENAMED
|
File without changes
|
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/change_user.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/comments.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/export.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/files.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/notifications.py
RENAMED
|
File without changes
|
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/query.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/stream.py
RENAMED
|
File without changes
|
{konecty_sdk_python-2.1.7 → konecty_sdk_python-2.2.0}/KonectySdkPython/lib/services/subscriptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|