-
-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathbitrix24.py
More file actions
104 lines (87 loc) · 3.71 KB
/
bitrix24.py
File metadata and controls
104 lines (87 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# -*- coding: utf-8 -*-
"""
Bitrix24
~~~~~~~~~~~~
This module implements the Bitrix24 REST API.
:copyright: (c) 2019 by Akop Kesheshyan.
"""
import requests
from time import sleep
from urllib.parse import urlparse
from .exceptions import BitrixError
class Bitrix24(object):
"""A user-created :class:`Bitrix24 <Bitrix24>` object.
Used to sent to the server.
:param domain: REST call domain, including account name, user ID and secret code.
:param timeout: (Optional) waiting for a response after a given number of seconds.
Usage::
>>> from bitrix24 import Bitrix24
>>> bx24 = Bitrix24('https://example.bitrix24.com/rest/1/33olqeits4avuyqu')
>>> bx24.callMethod('crm.product.list')
"""
def __init__(self, domain, timeout=60):
"""Create Bitrix24 API object
:param domain: str Bitrix24 webhook domain
:param timeout: int Timeout for API request in seconds
"""
self.domain = self._prepare_domain(domain)
self.timeout = timeout
def _prepare_domain(self, domain):
"""Normalize user passed domain to a valid one."""
if domain == '' or not isinstance(domain, str):
raise Exception('Empty domain')
o = urlparse(domain)
user_id, code = o.path.split('/')[2:4]
return "{0}://{1}/rest/{2}/{3}".format(o.scheme, o.netloc, user_id, code)
def _prepare_params(self, params, prev=''):
"""Transforms list of params to a valid bitrix array."""
ret = ''
if (isinstance(params, list) or isinstance(params, tuple)) and len(params) > 0:
params = dict(enumerate(params))
if isinstance(params, dict):
for key, value in params.items():
if (isinstance(params, list) or isinstance(params, tuple)) and len(params) > 0:
params = dict(enumerate(params))
if isinstance(value, dict):
if prev:
key = "{0}[{1}]".format(prev, key)
ret += self._prepare_params(value, key)
else:
if prev:
ret += "{0}[{1}]={2}&".format(prev, key, value)
else:
ret += "{0}={1}&".format(key, value)
return ret
def callMethod(self, method, **params):
"""Calls a REST method with specified parameters.
:param url: REST method name.
:param \*\*params: Optional arguments which will be converted to a POST request string.
:return: Returning the REST method response as an array, an object or a scalar
"""
try:
url = '{0}/{1}.json'.format(self.domain, method)
p = self._prepare_params(params)
if method.rsplit('.', 1)[0] in ['add', 'update', 'delete', 'set']:
r = requests.post(url, data=p, timeout=self.timeout).json()
else:
r = requests.get(url, params=p, timeout=self.timeout).json()
except ValueError:
if r['error'] not in 'QUERY_LIMIT_EXCEEDED':
raise BitrixError(r)
# Looks like we need to wait until expires limitation time by Bitrix24 API
sleep(2)
return self.callMethod(method, **params)
if 'error' in r:
raise BitrixError(r)
if 'start' not in params:
params['start'] = 0
if 'next' in r and r['total'] > params['start']:
params['start'] += 50
data = self.callMethod(method, **params)
if isinstance(r['result'], dict):
result = r['result'].copy()
result.update(data)
else:
result = r['result'] + data
return result
return r['result']