1
- # -*- coding: utf-8 -*-
1
+ # ____ _ _ _ ____ _ _ ____ _____ ____ _____
2
+ # | __ )(_) |_ _ __(_)_ _|___ \| || | | _ \| ____/ ___|_ _|
3
+ # | _ \| | __| '__| \ \/ / __) | || |_ | |_) | _| \___ \ | |
4
+ # | |_) | | |_| | | |> < / __/|__ _| | _ <| |___ ___) || |
5
+ # |____/|_|\__|_| |_/_/\_\_____| |_| |_| \_\_____|____/ |_|
2
6
3
- """
4
- Bitrix24
5
- ~~~~~~~~~~~~
6
-
7
- This module implements the Bitrix24 REST API.
8
-
9
- :copyright: (c) 2019 by Akop Kesheshyan.
10
-
11
- """
12
7
import warnings
13
-
14
- import requests
15
8
from time import sleep
16
9
from urllib .parse import urlparse
10
+
11
+ import requests
12
+
17
13
from .exceptions import BitrixError
18
14
19
15
20
- class Bitrix24 ( object ) :
21
- """A user-created :class:`Bitrix24 <Bitrix24>` object.
22
- Used to sent to the server .
16
+ class Bitrix24 :
17
+ """
18
+ Bitrix24 API class .
23
19
24
- :param domain: REST call domain, including account name, user ID and secret code.
25
- :param timeout: (Optional) waiting for a response after a given number of seconds.
26
- Usage::
27
- >>> from bitrix24 import Bitrix24
28
- >>> bx24 = Bitrix24('https://example.bitrix24.com/rest/1/33olqeits4avuyqu')
29
- >>> bx24.callMethod('crm.product.list')
20
+ Provides an easy way to communicate with Bitrix24 portal over REST without OAuth.
30
21
"""
31
22
32
- def __init__ (self , domain , timeout = 60 , safe = True ):
33
- """Create Bitrix24 API object
34
- :param domain: str Bitrix24 webhook domain
35
- :param timeout: int Timeout for API request in seconds
23
+ def __init__ (self , domain : str , timeout : int = 60 , safe : bool = True ):
24
+ """
25
+ Create Bitrix24 API object.
26
+
27
+ Parameters
28
+ ----------
29
+ domain (str): Bitrix24 webhook domain
30
+ timeout (int): Timeout for API request in seconds
36
31
"""
37
32
self .domain = self ._prepare_domain (domain )
38
33
self .timeout = timeout
39
34
self .safe = safe
40
35
41
- def _prepare_domain (self , domain ):
36
+ def _prepare_domain (self , domain : str ):
42
37
"""Normalize user passed domain to a valid one."""
43
- if domain == '' or not isinstance ( domain , str ) :
44
- raise Exception (' Empty domain' )
38
+ if not domain :
39
+ raise Exception (" Empty domain" )
45
40
46
41
o = urlparse (domain )
47
- user_id , code = o .path .split ('/' )[2 :4 ]
42
+ user_id , code = o .path .split ("/" )[2 :4 ]
48
43
return "{0}://{1}/rest/{2}/{3}" .format (o .scheme , o .netloc , user_id , code )
49
44
50
- def _prepare_params (self , params , prev = '' ):
51
- """Transforms list of params to a valid bitrix array."""
52
- ret = ''
45
+ def _prepare_params (self , params , prev = "" ):
46
+ """
47
+ Transform list of parameters to a valid bitrix array.
48
+
49
+ Parameters
50
+ ----------
51
+ params (dict): Dictionary of parameters
52
+ prev (str): Previous key
53
+
54
+ Returns
55
+ -------
56
+ str: Prepared parameters
57
+ """
58
+ ret = ""
53
59
if isinstance (params , dict ):
54
60
for key , value in params .items ():
55
61
if isinstance (value , dict ):
@@ -60,11 +66,11 @@ def _prepare_params(self, params, prev=''):
60
66
for offset , val in enumerate (value ):
61
67
if isinstance (val , dict ):
62
68
ret += self ._prepare_params (
63
- val , "{0}[{1}][{2}]" .format (prev , key , offset ))
69
+ val , "{0}[{1}][{2}]" .format (prev , key , offset )
70
+ )
64
71
else :
65
72
if prev :
66
- ret += "{0}[{1}][{2}]={3}&" .format (
67
- prev , key , offset , val )
73
+ ret += "{0}[{1}][{2}]={3}&" .format (prev , key , offset , val )
68
74
else :
69
75
ret += "{0}[{1}]={2}&" .format (key , offset , val )
70
76
else :
@@ -74,53 +80,63 @@ def _prepare_params(self, params, prev=''):
74
80
ret += "{0}={1}&" .format (key , value )
75
81
return ret
76
82
77
- def callMethod (self , method , ** params ):
78
- """Calls a REST method with specified parameters.
79
-
80
- :param url: REST method name.
81
- :param \*\*params: Optional arguments which will be converted to a POST request string.
82
- :return: Returning the REST method response as an array, an object or a scalar
83
- """
84
-
83
+ def request (self , url , method , p ):
84
+ if method .rsplit ("." , 1 )[0 ] in ["add" , "update" , "delete" , "set" ]:
85
+ r = requests .post (url , data = p , timeout = self .timeout , verify = self .safe ).json ()
86
+ else :
87
+ r = requests .get (url , params = p , timeout = self .timeout , verify = self .safe )
85
88
try :
86
- url = '{0}/{1}.json' .format (self .domain , method )
89
+ r = r .json ()
90
+ except requests .exceptions .JSONDecodeError :
91
+ warnings .warn ("bitrix24: JSON decode error..." )
92
+ if r .status_code == 403 :
93
+ warnings .warn (
94
+ f"bitrix24: Forbidden: { method } . "
95
+ "Check your bitrix24 webhook settings. Returning None! "
96
+ )
97
+ return None
98
+ elif r .ok :
99
+ return r .content
100
+
101
+ def callMethod (self , method : str , ** params ):
102
+ """Call a REST method with specified parameters.
103
+
104
+ Parameters
105
+ ----------
106
+ method (str): REST method name
107
+ params (dict): Optional arguments which will be converted to a POST request string
108
+
109
+ Returns
110
+ -------
111
+ Returning the REST method response as an array, an object or a scalar
112
+ """
113
+ if not method or len (method .split ("." )) < 3 :
114
+ raise BitrixError ("Empty method" )
87
115
116
+ try :
117
+ url = "{0}/{1}.json" .format (self .domain , method )
88
118
p = self ._prepare_params (params )
89
-
90
- if method .rsplit ('.' , 1 )[0 ] in ['add' , 'update' , 'delete' , 'set' ]:
91
- r = requests .post (url , data = p , timeout = self .timeout , verify = self .safe ).json ()
92
- else :
93
- r = requests .get (url , params = p , timeout = self .timeout , verify = self .safe )
94
- try :
95
- r = r .json ()
96
- except requests .exceptions .JSONDecodeError as e :
97
- warnings .warn ("bitrix24: JSON decode error..." )
98
- if r .status_code == 403 :
99
- warnings .warn (f"bitrix24: Forbidden: { method } . Check your bitrix24 webhook settings. Returning None! " )
100
- return None
101
- elif r .ok :
102
- return r .content
103
-
104
-
105
-
119
+ r = self .request (url , method , p )
120
+ if not r :
121
+ return None
106
122
except ValueError :
107
- if r [' error' ] not in ' QUERY_LIMIT_EXCEEDED' :
108
- raise BitrixError (r )
123
+ if r [" error" ] not in " QUERY_LIMIT_EXCEEDED" :
124
+ raise BitrixError (message = r [ "error_description" ], code = r [ "error" ] )
109
125
# Looks like we need to wait until expires limitation time by Bitrix24 API
110
126
sleep (2 )
111
127
return self .callMethod (method , ** params )
112
128
113
- if ' error' in r :
129
+ if " error" in r :
114
130
raise BitrixError (r )
115
- if ' start' not in params :
116
- params [' start' ] = 0
117
- if ' next' in r and r [' total' ] > params [' start' ]:
118
- params [' start' ] += 50
131
+ if " start" not in params :
132
+ params [" start" ] = 0
133
+ if " next" in r and r [" total" ] > params [" start" ]:
134
+ params [" start" ] += 50
119
135
data = self .callMethod (method , ** params )
120
- if isinstance (r [' result' ], dict ):
121
- result = r [' result' ].copy ()
136
+ if isinstance (r [" result" ], dict ):
137
+ result = r [" result" ].copy ()
122
138
result .update (data )
123
139
else :
124
- result = r [' result' ] + data
140
+ result = r [" result" ] + data
125
141
return result
126
- return r [' result' ]
142
+ return r [" result" ]
0 commit comments