amocrm-api-wrapper 0.0.20__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.
- amocrm_api/__init__.py +5 -0
- amocrm_api/base.py +4191 -0
- amocrm_api/errors.py +9 -0
- amocrm_api/legacy_client.py +58 -0
- amocrm_api/oauth_client.py +92 -0
- amocrm_api_wrapper-0.0.20.dist-info/METADATA +1232 -0
- amocrm_api_wrapper-0.0.20.dist-info/RECORD +9 -0
- amocrm_api_wrapper-0.0.20.dist-info/WHEEL +5 -0
- amocrm_api_wrapper-0.0.20.dist-info/top_level.txt +1 -0
amocrm_api/errors.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
class AmoException(Exception):
|
|
2
|
+
def __init__(self, error_data: dict, code: int = 500, *args):
|
|
3
|
+
self.error_data = error_data
|
|
4
|
+
self.code = code
|
|
5
|
+
super().__init__(args)
|
|
6
|
+
|
|
7
|
+
def __str__(self):
|
|
8
|
+
error_message = ''.join(f'{k}: {v}' for k, v in self.error_data.items())
|
|
9
|
+
return f'Code: {self.code}, Detail: {error_message}'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from json import JSONDecodeError
|
|
2
|
+
from requests import Session, ConnectionError, ConnectTimeout
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
from urllib.parse import urlencode
|
|
5
|
+
|
|
6
|
+
from .errors import AmoException
|
|
7
|
+
from .base import BaseClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AmoLegacyClient(BaseClient):
|
|
11
|
+
def __init__(self, login: str, token: str, crm_url: str) -> None:
|
|
12
|
+
"""Init
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
login (str): login
|
|
16
|
+
token (str): seckter token
|
|
17
|
+
crm_url (str): your crm url like https://example.amocrm.ru
|
|
18
|
+
"""
|
|
19
|
+
self.login = login
|
|
20
|
+
self.token = token
|
|
21
|
+
self.crm_url = crm_url if not crm_url.endswith('/') else crm_url[:-1]
|
|
22
|
+
self._session = self._init_session()
|
|
23
|
+
|
|
24
|
+
def _init_session(self, headers: Optional[dict] = None) -> Session:
|
|
25
|
+
"""Init session
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
headers (Optional[dict], optional): headers params. Defaults to None.
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
AmoException: if invalid auth data
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Session: session
|
|
35
|
+
"""
|
|
36
|
+
url = f"{self.crm_url}/private/api/auth.php?type=json"
|
|
37
|
+
params = {"USER_LOGIN": self.login, "USER_HASH": self.token}
|
|
38
|
+
session = Session()
|
|
39
|
+
if isinstance(headers, dict):
|
|
40
|
+
session.headers.update(**headers)
|
|
41
|
+
auth_response = session.post(url, json=params).json()
|
|
42
|
+
if auth_response.get("response", {}).get("auth", {}):
|
|
43
|
+
return session
|
|
44
|
+
raise AmoException(auth_response)
|
|
45
|
+
|
|
46
|
+
def _send_api_request(
|
|
47
|
+
self, method: str, url: str, data: Optional[dict] = None
|
|
48
|
+
) -> dict:
|
|
49
|
+
try:
|
|
50
|
+
response = self._session.__getattribute__(method)(url, json=data)
|
|
51
|
+
if response.status_code == 204:
|
|
52
|
+
return {}
|
|
53
|
+
json_data = response.json()
|
|
54
|
+
if 'error' in json_data:
|
|
55
|
+
raise AmoException(json_data)
|
|
56
|
+
return json_data
|
|
57
|
+
except (ConnectTimeout, ConnectionError, JSONDecodeError) as e:
|
|
58
|
+
raise AmoException({'error': str(e)})
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from json import JSONDecodeError
|
|
2
|
+
from requests import Session, ConnectionError, ConnectTimeout, post
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
from urllib.parse import urlencode
|
|
5
|
+
|
|
6
|
+
from .errors import AmoException
|
|
7
|
+
from .base import BaseClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AmoOAuthClient(BaseClient):
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
access_token: str,
|
|
14
|
+
refresh_token: str,
|
|
15
|
+
crm_url: str,
|
|
16
|
+
client_id: str,
|
|
17
|
+
client_secret: str,
|
|
18
|
+
redirect_uri: str,
|
|
19
|
+
):
|
|
20
|
+
self._access_token = access_token
|
|
21
|
+
self._refresh_token = refresh_token
|
|
22
|
+
self.crm_url = crm_url if not crm_url.endswith('/') else crm_url[:-1]
|
|
23
|
+
self.client_id = client_id
|
|
24
|
+
self.client_secret = client_secret
|
|
25
|
+
self.redirect_uri = redirect_uri
|
|
26
|
+
self._session = self._init_session()
|
|
27
|
+
|
|
28
|
+
def _init_session(self, params: Optional[dict] = None) -> Session:
|
|
29
|
+
session = Session()
|
|
30
|
+
session.headers.update(
|
|
31
|
+
{
|
|
32
|
+
'Authorization': f'Bearer {self.access_token}',
|
|
33
|
+
'User-Agent': 'amocrm-api-client/1.0',
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
if params:
|
|
37
|
+
session.headers.update(params)
|
|
38
|
+
return session
|
|
39
|
+
|
|
40
|
+
def _send_api_request(
|
|
41
|
+
self,
|
|
42
|
+
method: str,
|
|
43
|
+
url: str,
|
|
44
|
+
data: Optional[dict] = None,
|
|
45
|
+
update_tokens: bool = False,
|
|
46
|
+
) -> dict:
|
|
47
|
+
try:
|
|
48
|
+
response = super()._send_api_request(method, url, data)
|
|
49
|
+
return response
|
|
50
|
+
except AmoException as e:
|
|
51
|
+
if 'Jsonstatus: 401' in str(e) and not update_tokens:
|
|
52
|
+
self.update_tokens()
|
|
53
|
+
return self._send_api_request(method, url, data, True)
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
def update_session_auth_headers(self):
|
|
57
|
+
self.update_session_params({'Authorization': f'Bearer {self.access_token}'})
|
|
58
|
+
|
|
59
|
+
def update_tokens(self):
|
|
60
|
+
url = f'{self.crm_url}/oauth2/access_token'
|
|
61
|
+
params = {
|
|
62
|
+
'client_id': self.client_id,
|
|
63
|
+
'client_secret': self.client_secret,
|
|
64
|
+
'grant_type': 'refresh_token',
|
|
65
|
+
'refresh_token': self.refresh_token,
|
|
66
|
+
'redirect_uri': self.redirect_uri,
|
|
67
|
+
}
|
|
68
|
+
r = post(url, json=params)
|
|
69
|
+
data = r.json()
|
|
70
|
+
if r.status_code > 204:
|
|
71
|
+
raise AmoException(data)
|
|
72
|
+
self._update_token_params(data['access_token'], data['refresh_token'])
|
|
73
|
+
self.update_session_auth_headers()
|
|
74
|
+
|
|
75
|
+
def _update_token_params(self, access_token: str, refresh_token: str):
|
|
76
|
+
self._access_token = access_token
|
|
77
|
+
self._refresh_token = refresh_token
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def access_token(self) -> str:
|
|
81
|
+
return self._access_token
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def refresh_token(self) -> str:
|
|
85
|
+
return self._refresh_token
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def tokens(self) -> dict:
|
|
89
|
+
return {
|
|
90
|
+
'access_token': self.access_token,
|
|
91
|
+
'refresh_token': self.refresh_token,
|
|
92
|
+
}
|