konecty-sdk-python 2.1.7__tar.gz → 2.3.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.
Files changed (37) hide show
  1. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/client.py +12 -0
  2. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/exceptions.py +20 -0
  3. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/auth.py +69 -4
  4. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/PKG-INFO +1 -1
  5. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/pyproject.toml +1 -1
  6. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/.gitignore +0 -0
  7. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/__init__.py +0 -0
  8. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/cli/__init__.py +0 -0
  9. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/cli/apply.py +0 -0
  10. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/cli/backup.py +0 -0
  11. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/cli/pull.py +0 -0
  12. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/__init__.py +0 -0
  13. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/feature_types/__init__.py +0 -0
  14. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/feature_types/cross_module_query.py +0 -0
  15. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/feature_types/kpi.py +0 -0
  16. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/feature_types/query_json.py +0 -0
  17. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/file_manager.py +0 -0
  18. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/filters.py +0 -0
  19. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/http.py +0 -0
  20. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/model.py +0 -0
  21. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/serialization.py +0 -0
  22. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/__init__.py +0 -0
  23. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/admin.py +0 -0
  24. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/aggregation.py +0 -0
  25. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/base.py +0 -0
  26. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/change_user.py +0 -0
  27. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/comments.py +0 -0
  28. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/export.py +0 -0
  29. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/files.py +0 -0
  30. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/notifications.py +0 -0
  31. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/pat.py +0 -0
  32. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/query.py +0 -0
  33. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/stream.py +0 -0
  34. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/services/subscriptions.py +0 -0
  35. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/settings.py +0 -0
  36. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.0}/KonectySdkPython/lib/types.py +0 -0
  37. {konecty_sdk_python-2.1.7 → konecty_sdk_python-2.3.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 KonectyAPIError, KonectyGoogleSessionError
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
- def _first_error_code(error: KonectyAPIError) -> str:
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 _GOOGLE_SESSION_ERROR_CODES:
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. Keys are the wire names, as in the TypeScript SDK.
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: konecty_sdk_python
3
- Version: 2.1.7
3
+ Version: 2.3.0
4
4
  Summary: Konecty SDK Python
5
5
  Author-email: Leonardo Leal <leonardo.leal@konecty.com>, Derotino Silveira <derotino.silveira@konecty.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "konecty_sdk_python"
3
- version = "2.1.7"
3
+ version = "2.3.0"
4
4
  description = "Konecty SDK Python"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"