1- # -*- coding: utf-8 -*-
1+ # ____ _ _ _ ____ _ _ ____ _____ ____ _____
2+ # | __ )(_) |_ _ __(_)_ _|___ \| || | | _ \| ____/ ___|_ _|
3+ # | _ \| | __| '__| \ \/ / __) | || |_ | |_) | _| \___ \ | |
4+ # | |_) | | |_| | | |> < / __/|__ _| | _ <| |___ ___) || |
5+ # |____/|_|\__|_| |_/_/\_\_____| |_| |_| \_\_____|____/ |_|
26
3- """
4- Bitrix24
5- ~~~~~~~~~~~~
6-
7- This module implements the Bitrix24 REST API.
8-
9- :copyright: (c) 2019 by Akop Kesheshyan.
10-
11- """
127import warnings
13-
14- import requests
158from time import sleep
169from urllib .parse import urlparse
10+
11+ import requests
12+
1713from .exceptions import BitrixError
1814
1915
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 .
2319
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.
3021 """
3122
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
3631 """
3732 self .domain = self ._prepare_domain (domain )
3833 self .timeout = timeout
3934 self .safe = safe
4035
41- def _prepare_domain (self , domain ):
36+ def _prepare_domain (self , domain : str ):
4237 """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" )
4540
4641 o = urlparse (domain )
47- user_id , code = o .path .split ('/' )[2 :4 ]
42+ user_id , code = o .path .split ("/" )[2 :4 ]
4843 return "{0}://{1}/rest/{2}/{3}" .format (o .scheme , o .netloc , user_id , code )
4944
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 = ""
5359 if isinstance (params , dict ):
5460 for key , value in params .items ():
5561 if isinstance (value , dict ):
@@ -60,11 +66,11 @@ def _prepare_params(self, params, prev=''):
6066 for offset , val in enumerate (value ):
6167 if isinstance (val , dict ):
6268 ret += self ._prepare_params (
63- val , "{0}[{1}][{2}]" .format (prev , key , offset ))
69+ val , "{0}[{1}][{2}]" .format (prev , key , offset )
70+ )
6471 else :
6572 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 )
6874 else :
6975 ret += "{0}[{1}]={2}&" .format (key , offset , val )
7076 else :
@@ -74,53 +80,63 @@ def _prepare_params(self, params, prev=''):
7480 ret += "{0}={1}&" .format (key , value )
7581 return ret
7682
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 )
8588 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" )
87115
116+ try :
117+ url = "{0}/{1}.json" .format (self .domain , method )
88118 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
106122 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" ] )
109125 # Looks like we need to wait until expires limitation time by Bitrix24 API
110126 sleep (2 )
111127 return self .callMethod (method , ** params )
112128
113- if ' error' in r :
129+ if " error" in r :
114130 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
119135 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 ()
122138 result .update (data )
123139 else :
124- result = r [' result' ] + data
140+ result = r [" result" ] + data
125141 return result
126- return r [' result' ]
142+ return r [" result" ]
0 commit comments