Module centralnicreseller.apiconnector.apiclient
centralnicreseller.apiconnector.apiclient ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This module covers all necessary functionality for http communicatiton with our Backend System. :copyright: © 2024 Team Internet Group PLC. :license: MIT, see LICENSE for more details.
Classes
class APIClient
-
Expand source code
class APIClient(object): def __init__(self): # API connection url self.setURL(CNR_CONNECTION_URL_LIVE) # Object covering API connection data self.__socketConfig = SocketConfig() # activity flag for debug mode self.__debugMode = False # API connection timeout setting self.__socketTimeout = 300 * 1000 self.useLIVESystem() # user agent setting self.__ua = "" # additional connection settings self.__curlopts = {} # logger class instance self.setDefaultLogger() # subuser account name (subuser specific data view) self.__subUser = None # login role seperator self.__roleSeparator = ":" def setCustomLogger(self, logger): """ Set custom logger to use instead of the default one """ self.__logger = logger return self def setDefaultLogger(self): """ Set default logger to use """ self.__logger = Logger() return self def setProxy(self, proxy): """ Set Proxy to use for API communication """ if proxy == "": self.__curlopts.pop("PROXY", None) else: self.__curlopts["PROXY"] = proxy return self def getProxy(self): """ Get Proxy configuration value for API communication """ if "PROXY" in self.__curlopts: return self.__curlopts["PROXY"] return None def setReferer(self, referer): """ Set the Referer Header to use for API communication """ if referer == "": self.__curlopts.pop("REFERER", None) else: self.__curlopts["REFERER"] = referer return self def getReferer(self): """ Get the Referer Header configuration value """ if "REFERER" in self.__curlopts: return self.__curlopts["REFERER"] return None def enableDebugMode(self): """ Enable Debug Output to STDOUT """ self.__debugMode = True return self def disableDebugMode(self): """ Disable Debug Output """ self.__debugMode = False return self def getPOSTData(self, cmd, secured=False): """ Serialize given command for POST request including connection configuration data """ data = self.__socketConfig.getPOSTData() if secured: data = re.sub(r"s_pw=[^&]+", "s_pw=***", data) if isinstance(cmd, str): tmp = cmd.rstrip("\n") else: tmp = "\n".join( "{}={}".format(key, re.sub(r'[\r\n]', '', str(cmd[key]))) for key in sorted(cmd.keys()) if cmd[key] is not None ) if secured: tmp = re.sub(r"PASSWORD=[^\n]+", "PASSWORD=***", tmp) if tmp: return f"{data}{quote('s_command')}={quote(tmp)}" else: return data if not data.endswith('&') else data.rstrip('&') def getURL(self): """ Get the API connection url that is currently set """ return self.__socketURL def getUserAgent(self): """ Get the User Agent """ if len(self.__ua) == 0: pid = "PYTHON-SDK" pyv = platform.python_version() pf = platform.system() arch = platform.architecture()[0] self.__ua = "%s (%s; %s; rv:%s) python/%s" % ( pid, pf, arch, self.getVersion(), pyv, ) return self.__ua def setUserAgent(self, pid, rv, modules=[]): """ Possibility to customize default user agent to fit your needs by given string and revision """ s = " " mods = "" if len(modules) > 0: mods += " " + s.join(modules) pyv = platform.python_version() pf = platform.system() arch = platform.architecture()[0] self.__ua = "%s (%s; %s; rv:%s)%s python-sdk/%s python/%s" % ( pid, pf, arch, rv, mods, self.getVersion(), pyv, ) return self def getVersion(self): """ Get the current module version """ return "5.0.0" def saveSession(self, session): """ Apply session data (session id and user login) to given client request session """ session["socketcfg"] = { "login": self.__socketConfig.getLogin(), "session": self.__socketConfig.getSession(), } return self def reuseSession(self, session): """ Use existing configuration out of session to rebuild and reuse connection settings """ if not session or "socketcfg" not in session or "login" not in session["socketcfg"] or "session" not in session["socketcfg"]: return self self.setCredentials(session["socketcfg"]["login"]) self.__socketConfig.setSession(session["socketcfg"]["session"]) return self def setURL(self, value): """ Set another connection url to be used for API communication """ self.__socketURL = value return self def setPersistent(self): """echo Set persistent connection to be used for API communication """ self.__socketConfig.setPersistent() return self def setCredentials(self, uid, pw=""): """ Set Credentials to be used for API communication """ self.__socketConfig.setLogin(uid) self.__socketConfig.setPassword(pw) return self def setRoleCredentials(self, uid, role, pw = ""): """ Set Credentials to be used for API communication """ if role == "": return self.setCredentials(uid, pw) return self.setCredentials(("{0}{1}{2}").format(uid, self.__roleSeparator, role), pw) def login(self): """ Perform API login to start session-based communication """ self.setPersistent() rr = self.request([], False) self.__socketConfig.setSession(None) # clean up all session related data if rr.isSuccess(): col = rr.getColumn("SESSIONID") self.__socketConfig.setSession(col.getData()[0] if (col is not None) else None) return rr def logout(self): """ Perform API logout to close API session in use """ rr = self.request( { "COMMAND": "StopSession", } ) if rr.isSuccess(): self.__socketConfig.setSession(None) # clean up all session related data return rr def request(self, cmd=[], setUserView=True): """ Perform API request using the given command """ newcmd = {} if (cmd is not None) and (len(cmd) > 0): # if subuser is set, add it to the command if setUserView and self.__subUser is not None: cmd["SUBUSER"] = self.__subUser # flatten nested api command bulk parameters newcmd = self.__flattenCommand(cmd) # auto convert umlaut names to punycode newcmd = self.__autoIDNConvert(newcmd) # request command to API cfg = {"CONNECTION_URL": self.__socketURL} data = self.getPOSTData(newcmd).encode("UTF-8") secured = self.getPOSTData(newcmd, True).encode("UTF-8") error = None try: headers = {"User-Agent": self.getUserAgent()} if "REFERER" in self.__curlopts: headers["Referer"] = self.__curlopts["REFERER"] req = Request(cfg["CONNECTION_URL"], data, headers) if "PROXY" in self.__curlopts: proxyurl = urlparse(self.__curlopts["PROXY"]) req.set_proxy(proxyurl.netloc, proxyurl.scheme) body = urlopen(req, timeout=self.__socketTimeout).read() except Exception as e: error = str(e) body = rtm.getTemplate("httperror").getPlain() r = Response(body, newcmd, cfg) if self.__debugMode: self.__logger.log(secured, r, error) return r def requestNextResponsePage(self, rr): """ Request the next page of list entries for the current list query Useful for tables """ mycmd = rr.getCommand() if "LAST" in mycmd: raise Exception( "Parameter LAST in use. Please remove it to avoid issues in requestNextPage." ) first = 0 if "FIRST" in mycmd: first = int(mycmd["FIRST"]) total = rr.getRecordsTotalCount() limit = rr.getRecordsLimitation() first += limit if first < total: mycmd["FIRST"] = first mycmd["LIMIT"] = limit return self.request(mycmd) else: return None def requestAllResponsePages(self, cmd): """ Request all pages/entries for the given query command """ responses = [] mycmd = copy.deepcopy(cmd) mycmd["FIRST"] = 0 rr = self.request(mycmd) tmp = rr while tmp is not None: responses.append(tmp) tmp = self.requestNextResponsePage(tmp) if tmp is None: break return responses def setUserView(self, uid): """ Set a data view to a given subuser """ self.__subUser = uid return self def resetUserView(self): """ Reset data view back from subuser to user """ self.__subUser = None return self def useHighPerformanceConnectionSetup(self): """ Activate High Performance Setup """ self.setURL(CNR_CONNECTION_URL_PROXY) return self def useDefaultConnectionSetup(self): """ Activate Default Connection Setup (which is the default anyways) """ self.setURL(CNR_CONNECTION_URL_LIVE) return self def useOTESystem(self): """ Set OT&E System for API communication """ self.setURL(CNR_CONNECTION_URL_OTE) return self def useLIVESystem(self): """ Set LIVE System for API communication (this is the default setting) """ self.setURL(CNR_CONNECTION_URL_LIVE) return self def __flattenCommand(self, cmd): """ Flatten API command to handle it easier later on (nested array for bulk params) """ newcmd = {} for key in list(cmd.keys()): newKey = key.upper() val = cmd[key] if val is None: continue if isinstance(val, list): i = 0 while i < len(val): newcmd[newKey + str(i)] = re.sub(r"[\r\n]", "", str(val[i])) i += 1 else: newcmd[newKey] = re.sub(r"[\r\n]", "", str(val)) return newcmd def __autoIDNConvert(self, cmd): """ Converts domain names in the cmd dictionary to their ASCII (Punycode) representations. """ key_pattern = re.compile(r"(?i)^(NAMESERVER|NS|DNSZONE)([0-9]*)$") obj_class_pattern = re.compile( r"(?i)^(DOMAIN(APPLICATION|BLOCKING)?|NAMESERVER|NS|DNSZONE)$") ascii_pattern = re.compile(r"^[A-Za-z0-9.\-]+$") to_convert = [] idxs = [] for key, val in cmd.items(): if ((key_pattern.match(key) or (key.upper() == "OBJECTID" and obj_class_pattern.match(cmd.get("OBJECTCLASS", "")))) and not ascii_pattern.match(val)): to_convert.append(val) idxs.append(key) if to_convert: result = IDNAConverter.convert_list(to_convert) pc_list = result.get_pc_list() for idx, converted_value in zip(idxs, pc_list): cmd[idx] = converted_value return cmd
Methods
def disableDebugMode(self)
-
Expand source code
def disableDebugMode(self): """ Disable Debug Output """ self.__debugMode = False return self
Disable Debug Output
def enableDebugMode(self)
-
Expand source code
def enableDebugMode(self): """ Enable Debug Output to STDOUT """ self.__debugMode = True return self
Enable Debug Output to STDOUT
def getPOSTData(self, cmd, secured=False)
-
Expand source code
def getPOSTData(self, cmd, secured=False): """ Serialize given command for POST request including connection configuration data """ data = self.__socketConfig.getPOSTData() if secured: data = re.sub(r"s_pw=[^&]+", "s_pw=***", data) if isinstance(cmd, str): tmp = cmd.rstrip("\n") else: tmp = "\n".join( "{}={}".format(key, re.sub(r'[\r\n]', '', str(cmd[key]))) for key in sorted(cmd.keys()) if cmd[key] is not None ) if secured: tmp = re.sub(r"PASSWORD=[^\n]+", "PASSWORD=***", tmp) if tmp: return f"{data}{quote('s_command')}={quote(tmp)}" else: return data if not data.endswith('&') else data.rstrip('&')
Serialize given command for POST request including connection configuration data
def getProxy(self)
-
Expand source code
def getProxy(self): """ Get Proxy configuration value for API communication """ if "PROXY" in self.__curlopts: return self.__curlopts["PROXY"] return None
Get Proxy configuration value for API communication
def getReferer(self)
-
Expand source code
def getReferer(self): """ Get the Referer Header configuration value """ if "REFERER" in self.__curlopts: return self.__curlopts["REFERER"] return None
Get the Referer Header configuration value
def getURL(self)
-
Expand source code
def getURL(self): """ Get the API connection url that is currently set """ return self.__socketURL
Get the API connection url that is currently set
def getUserAgent(self)
-
Expand source code
def getUserAgent(self): """ Get the User Agent """ if len(self.__ua) == 0: pid = "PYTHON-SDK" pyv = platform.python_version() pf = platform.system() arch = platform.architecture()[0] self.__ua = "%s (%s; %s; rv:%s) python/%s" % ( pid, pf, arch, self.getVersion(), pyv, ) return self.__ua
Get the User Agent
def getVersion(self)
-
Expand source code
def getVersion(self): """ Get the current module version """ return "5.0.0"
Get the current module version
def login(self)
-
Expand source code
def login(self): """ Perform API login to start session-based communication """ self.setPersistent() rr = self.request([], False) self.__socketConfig.setSession(None) # clean up all session related data if rr.isSuccess(): col = rr.getColumn("SESSIONID") self.__socketConfig.setSession(col.getData()[0] if (col is not None) else None) return rr
Perform API login to start session-based communication
def logout(self)
-
Expand source code
def logout(self): """ Perform API logout to close API session in use """ rr = self.request( { "COMMAND": "StopSession", } ) if rr.isSuccess(): self.__socketConfig.setSession(None) # clean up all session related data return rr
Perform API logout to close API session in use
def request(self, cmd=[], setUserView=True)
-
Expand source code
def request(self, cmd=[], setUserView=True): """ Perform API request using the given command """ newcmd = {} if (cmd is not None) and (len(cmd) > 0): # if subuser is set, add it to the command if setUserView and self.__subUser is not None: cmd["SUBUSER"] = self.__subUser # flatten nested api command bulk parameters newcmd = self.__flattenCommand(cmd) # auto convert umlaut names to punycode newcmd = self.__autoIDNConvert(newcmd) # request command to API cfg = {"CONNECTION_URL": self.__socketURL} data = self.getPOSTData(newcmd).encode("UTF-8") secured = self.getPOSTData(newcmd, True).encode("UTF-8") error = None try: headers = {"User-Agent": self.getUserAgent()} if "REFERER" in self.__curlopts: headers["Referer"] = self.__curlopts["REFERER"] req = Request(cfg["CONNECTION_URL"], data, headers) if "PROXY" in self.__curlopts: proxyurl = urlparse(self.__curlopts["PROXY"]) req.set_proxy(proxyurl.netloc, proxyurl.scheme) body = urlopen(req, timeout=self.__socketTimeout).read() except Exception as e: error = str(e) body = rtm.getTemplate("httperror").getPlain() r = Response(body, newcmd, cfg) if self.__debugMode: self.__logger.log(secured, r, error) return r
Perform API request using the given command
def requestAllResponsePages(self, cmd)
-
Expand source code
def requestAllResponsePages(self, cmd): """ Request all pages/entries for the given query command """ responses = [] mycmd = copy.deepcopy(cmd) mycmd["FIRST"] = 0 rr = self.request(mycmd) tmp = rr while tmp is not None: responses.append(tmp) tmp = self.requestNextResponsePage(tmp) if tmp is None: break return responses
Request all pages/entries for the given query command
def requestNextResponsePage(self, rr)
-
Expand source code
def requestNextResponsePage(self, rr): """ Request the next page of list entries for the current list query Useful for tables """ mycmd = rr.getCommand() if "LAST" in mycmd: raise Exception( "Parameter LAST in use. Please remove it to avoid issues in requestNextPage." ) first = 0 if "FIRST" in mycmd: first = int(mycmd["FIRST"]) total = rr.getRecordsTotalCount() limit = rr.getRecordsLimitation() first += limit if first < total: mycmd["FIRST"] = first mycmd["LIMIT"] = limit return self.request(mycmd) else: return None
Request the next page of list entries for the current list query Useful for tables
def resetUserView(self)
-
Expand source code
def resetUserView(self): """ Reset data view back from subuser to user """ self.__subUser = None return self
Reset data view back from subuser to user
def reuseSession(self, session)
-
Expand source code
def reuseSession(self, session): """ Use existing configuration out of session to rebuild and reuse connection settings """ if not session or "socketcfg" not in session or "login" not in session["socketcfg"] or "session" not in session["socketcfg"]: return self self.setCredentials(session["socketcfg"]["login"]) self.__socketConfig.setSession(session["socketcfg"]["session"]) return self
Use existing configuration out of session to rebuild and reuse connection settings
def saveSession(self, session)
-
Expand source code
def saveSession(self, session): """ Apply session data (session id and user login) to given client request session """ session["socketcfg"] = { "login": self.__socketConfig.getLogin(), "session": self.__socketConfig.getSession(), } return self
Apply session data (session id and user login) to given client request session
def setCredentials(self, uid, pw='')
-
Expand source code
def setCredentials(self, uid, pw=""): """ Set Credentials to be used for API communication """ self.__socketConfig.setLogin(uid) self.__socketConfig.setPassword(pw) return self
Set Credentials to be used for API communication
def setCustomLogger(self, logger)
-
Expand source code
def setCustomLogger(self, logger): """ Set custom logger to use instead of the default one """ self.__logger = logger return self
Set custom logger to use instead of the default one
def setDefaultLogger(self)
-
Expand source code
def setDefaultLogger(self): """ Set default logger to use """ self.__logger = Logger() return self
Set default logger to use
def setPersistent(self)
-
Expand source code
def setPersistent(self): """echo Set persistent connection to be used for API communication """ self.__socketConfig.setPersistent() return self
echo Set persistent connection to be used for API communication
def setProxy(self, proxy)
-
Expand source code
def setProxy(self, proxy): """ Set Proxy to use for API communication """ if proxy == "": self.__curlopts.pop("PROXY", None) else: self.__curlopts["PROXY"] = proxy return self
Set Proxy to use for API communication
def setReferer(self, referer)
-
Expand source code
def setReferer(self, referer): """ Set the Referer Header to use for API communication """ if referer == "": self.__curlopts.pop("REFERER", None) else: self.__curlopts["REFERER"] = referer return self
Set the Referer Header to use for API communication
def setRoleCredentials(self, uid, role, pw='')
-
Expand source code
def setRoleCredentials(self, uid, role, pw = ""): """ Set Credentials to be used for API communication """ if role == "": return self.setCredentials(uid, pw) return self.setCredentials(("{0}{1}{2}").format(uid, self.__roleSeparator, role), pw)
Set Credentials to be used for API communication
def setURL(self, value)
-
Expand source code
def setURL(self, value): """ Set another connection url to be used for API communication """ self.__socketURL = value return self
Set another connection url to be used for API communication
def setUserAgent(self, pid, rv, modules=[])
-
Expand source code
def setUserAgent(self, pid, rv, modules=[]): """ Possibility to customize default user agent to fit your needs by given string and revision """ s = " " mods = "" if len(modules) > 0: mods += " " + s.join(modules) pyv = platform.python_version() pf = platform.system() arch = platform.architecture()[0] self.__ua = "%s (%s; %s; rv:%s)%s python-sdk/%s python/%s" % ( pid, pf, arch, rv, mods, self.getVersion(), pyv, ) return self
Possibility to customize default user agent to fit your needs by given string and revision
def setUserView(self, uid)
-
Expand source code
def setUserView(self, uid): """ Set a data view to a given subuser """ self.__subUser = uid return self
Set a data view to a given subuser
def useDefaultConnectionSetup(self)
-
Expand source code
def useDefaultConnectionSetup(self): """ Activate Default Connection Setup (which is the default anyways) """ self.setURL(CNR_CONNECTION_URL_LIVE) return self
Activate Default Connection Setup (which is the default anyways)
def useHighPerformanceConnectionSetup(self)
-
Expand source code
def useHighPerformanceConnectionSetup(self): """ Activate High Performance Setup """ self.setURL(CNR_CONNECTION_URL_PROXY) return self
Activate High Performance Setup
def useLIVESystem(self)
-
Expand source code
def useLIVESystem(self): """ Set LIVE System for API communication (this is the default setting) """ self.setURL(CNR_CONNECTION_URL_LIVE) return self
Set LIVE System for API communication (this is the default setting)
def useOTESystem(self)
-
Expand source code
def useOTESystem(self): """ Set OT&E System for API communication """ self.setURL(CNR_CONNECTION_URL_OTE) return self
Set OT&E System for API communication