def check_retrieve_status(self, async_process_id): """ After async process is done, post a checkRetrieveStatus to obtain the zipFile(base64) @async_process_id: retrieve request asyncProcessId """ server_url = globals()[self.username]['instance_url'] + "/services/Soap/m/28.0" headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } soap_body = soap_bodies.check_retrieve_status_body.format( session_id=globals()[self.username]["session_id"], async_process_id=async_process_id) response = requests.post(server_url, soap_body, verify=False, headers=headers) # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString(content, "errorCode") result["message"] = getUniqueElementValueFromXmlString(content, "message") return result result["zipFile"] = getUniqueElementValueFromXmlString(content, "zipFile") return result
def retrieve_all(self): """ 1. Issue a retrieve request to start the asynchronous retrieval and asyncProcessId is returned 2. Thread sleep for a while and then issue a checkStatus request to check whether the async process job is completed. 3. After the job is completed, issue a checkRetrieveStatus request to obtain the zipFile(base64) in the retrieve result. 4. Use Python Lib base64 to convert the base64 string to zip file. 5. Use Python Lib zipFile to unzip the zip file to path """ # Firstly Login self.login(False) # 1. Issue a retrieve request to start the asynchronous retrieval server_url = globals()[self.username]['instance_url'] + "/services/Soap/m/28.0" headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } # Populate the soap_body with actual session id soap_body = soap_bodies.retrieve_all_task_body.format( session_id=globals()[self.username]["session_id"]) response = requests.post(server_url, soap_body, verify=False, headers=headers) # Check whether session_id is expired if "INVALID_SESSION_ID" in response.text: self.login(True) return self.retrieve_all() # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString(content, "errorCode") result["message"] = getUniqueElementValueFromXmlString(content, "message") self.result = result return # Get async process id async_process_id = getUniqueElementValueFromXmlString(content, "id") print ("asyncProcessId: " + async_process_id) # 2. issue a check status loop request to assure the async # process is done result = self.check_status(async_process_id) # If check status request failed, this will not be done print (result) if result["done"] == "Failed": self.result = result return # 3 Obtain zipFile(base64) print ("Downloading zipFile in this retrieve result...") result = self.check_retrieve_status(async_process_id) self.result = result
def check_status(self, async_process_id): """ Ensure the retrieve request is done and then we can continue other work @async_process_id: retrieve request asyncProcessId """ # Thread sleep for 10 seconds print("Retrieve is in progress, please wait for 30 seconds.") time.sleep(30) # Check the status of retrieve job server_url = globals()[ self.username]['instance_url'] + "/services/Soap/m/28.0" headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } soap_body = soap_bodies.check_status_body.format( session_id=globals()[self.username]["session_id"], async_process_id=async_process_id) response = requests.post(server_url, soap_body, verify=False, headers=headers) # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString( content, "errorCode") result["message"] = getUniqueElementValueFromXmlString( content, "message") result["done"] = "Failed" return result # Get the retrieve status done = getUniqueElementValueFromXmlString(content, "done") # If retrieve is not done, sleep 10s and check again if done == "false": return self.check_status(async_process_id) # If retrieve is done result["done"] = True result["state"] = getUniqueElementValueFromXmlString(content, "state") return result
def execute_anonymous(self, apex_string): """ Generate a new view to display executed reusult of Apex Snippet :apex_string: Apex Snippet """ # Firstly Login self.login(False) server_url = globals()[self.username]['instance_url'] + "/services/Soap/s/27.0" # https://gist.github.com/richardvanhook/1245068 headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } # If we don't quote <, >, & in body, we will get below exception # Element type "String" must be followed by either attribute specifications, ">" or "/>" # http://wiki.python.org/moin/EscapingXml apex_string = quoteattr(apex_string).replace('"', '') soap_body = soap_bodies.execute_anonymous_body.format( session_id=globals()[self.username]["session_id"], apex_string = apex_string) response = requests.post(server_url, soap_body, verify=False, headers=headers) # Check whether session_id is expired if "INVALID_SESSION_ID" in response.text: self.login(True) return self.execute_anonymous(apex_string) # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString(content, "errorCode") result["message"] = getUniqueElementValueFromXmlString(content, "message") self.result = result return result # If execute anonymous succeed, just display message with a new view result["debugLog"] = unescape(getUniqueElementValueFromXmlString(content, "debugLog")) result["column"] = getUniqueElementValueFromXmlString(content, "column") result["compileProblem"] = unescape(getUniqueElementValueFromXmlString(content, "compileProblem")) result["compiled"] = getUniqueElementValueFromXmlString(content, "compiled") result["line"] = getUniqueElementValueFromXmlString(content, "line") result["success"] = getUniqueElementValueFromXmlString(content, "success") pprint.pprint (result) # Self.result is used to keep thread result self.result = result # This result is used for invoker return result
def soap_login(settings, timeout=120): login_soap_request_body = soap_bodies.login_body.format( username=settings["username"], password=settings["password"] + settings["security_token"]) login_soap_request_headers = { 'content-type': 'text/xml', 'charset': 'UTF-8', 'SOAPAction': 'login' } response = requests.post(settings["soap_login_url"], login_soap_request_body, verify=False, headers=login_soap_request_headers, timeout=timeout) result = {} if response.status_code != 200: except_code = getUniqueElementValueFromXmlString( response.content, 'sf:exceptionCode') except_msg = getUniqueElementValueFromXmlString( response.content, 'sf:exceptionMessage') result["errorCode"] = except_code result["message"] = except_msg result["status_code"] = response.status_code return result session_id = getUniqueElementValueFromXmlString(response.content, 'sessionId') server_url = getUniqueElementValueFromXmlString(response.content, 'serverUrl') sf_instance = server_url[:server_url.find('/services')] user_id = getUniqueElementValueFromXmlString(response.content, 'userId') print("session_id", session_id) result = { "session_id": session_id, "server_url": server_url, "instance_url": sf_instance, "user_id": user_id, "status_code": response.status_code } return result
def check_status(self, async_process_id): """ Ensure the retrieve request is done and then we can continue other work @async_process_id: retrieve request asyncProcessId """ # Thread sleep for 10 seconds print ("Retrieve is in progress, please wait for 30 seconds.") time.sleep(30) # Check the status of retrieve job server_url = globals()[self.username]['instance_url'] + "/services/Soap/m/28.0" headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } soap_body = soap_bodies.check_status_body.format( session_id=globals()[self.username]["session_id"], async_process_id=async_process_id) response = requests.post(server_url, soap_body, verify=False, headers=headers) # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString(content, "errorCode") result["message"] = getUniqueElementValueFromXmlString(content, "message") result["done"] = "Failed" return result # Get the retrieve status done = getUniqueElementValueFromXmlString(content, "done") # If retrieve is not done, sleep 10s and check again if done == "false": return self.check_status(async_process_id) # If retrieve is done result["done"] = True result["state"] = getUniqueElementValueFromXmlString(content, "state") return result
def create_batch(job_id, sobject, sobject_soql): url = globals()["instance_url"] +\ "/services/async/27.0/job/{job_id}/batch".format(job_id = job_id) headers = { "X-SFDC-Session": access_token, "Content-Type": "text/csv; charset=UTF-8" } response = requests.post(url, sobject_soql, verify = False, headers = headers) batch_id = getUniqueElementValueFromXmlString(response.content, "id") return batch_id
def get_batch_result_id(sobject, job_id, batch_id): url = globals()["instance_url"] +\ "/services/async/27.0/job/{job_id}/batch/{batch_id}/result".format(job_id = job_id, batch_id = batch_id) headers = { "X-SFDC-Session": access_token } response = requests.get(url, data = None, verify = False, headers = headers) result_id = getUniqueElementValueFromXmlString(response.content, "result") return result_id
def soap_login(settings, timeout=120): login_soap_request_body = soap_bodies.login_body.format( username=settings["username"], password=settings["password"] + settings["security_token"] ) login_soap_request_headers = {"content-type": "text/xml", "charset": "UTF-8", "SOAPAction": "login"} response = requests.post( settings["soap_login_url"], login_soap_request_body, verify=False, headers=login_soap_request_headers, timeout=timeout, ) result = {} if response.status_code != 200: except_code = getUniqueElementValueFromXmlString(response.content, "sf:exceptionCode") except_msg = getUniqueElementValueFromXmlString(response.content, "sf:exceptionMessage") result["errorCode"] = except_code result["message"] = except_msg result["status_code"] = response.status_code return result session_id = getUniqueElementValueFromXmlString(response.content, "sessionId") server_url = getUniqueElementValueFromXmlString(response.content, "serverUrl") sf_instance = server_url[: server_url.find("/services")] user_id = getUniqueElementValueFromXmlString(response.content, "userId") print("session_id", session_id) result = { "session_id": session_id, "server_url": server_url, "instance_url": sf_instance, "user_id": user_id, "status_code": response.status_code, } return result
def check_batch_status(job_id, batch_id, sobject): url = globals()["instance_url"] +\ "/services/async/27.0/job/{job_id}/batch/{batch_id}".format(job_id = job_id, batch_id = batch_id) headers = { "X-SFDC-Session": access_token } response = requests.get(url, data = None, verify = False, headers = headers) batch_status = getUniqueElementValueFromXmlString(response.content, "state") if batch_status == "Failed": error_message = getUniqueElementValueFromXmlString(response.content, "stateMessage") print(batch_id + " failed, because " + error_message) return False while batch_status != "Completed": print(sobject + " is not completed, please continue waiting...") time.sleep(15) check_batch_status(job_id, batch_id, sobject) return True
def login(username, password, securityToken, sandbox=False): if sandbox: soapUrl = "https://test.salesforce.com/services/Soap/u/23.0" else: soapUrl = "https://login.salesforce.com/services/Soap/u/23.0" loginSoapRequestBody = """<?xml version="1.0" encoding="utf-8" ?> <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> <env:Body> <n1:login xmlns:n1="urn:partner.soap.sforce.com"> <n1:username>%s</n1:username> <n1:password>%s%s</n1:password> </n1:login> </env:Body> </env:Envelope>""" % (username, password, securityToken) loginSoapRequestHeaders = { "content-type":"text/xml", "charset":"UTF-8", "SOAPAction":"login" } response = requests.post(soapUrl, loginSoapRequestBody, headers=loginSoapRequestHeaders) if response.status_code != 200: exception_code = getUniqueElementValueFromXmlString(response.content, 'sf:exceptionCode') exception_message = getUniqueElementValueFromXmlString(response.content, 'sf:exceptionMessage') raise SalesforceAuthenticationFailedException('%s: %s' % (exception_code, exception_message)) sessionId = getUniqueElementValueFromXmlString(response.content, 'sessionId') serverUrl = getUniqueElementValueFromXmlString(response.content, 'serverUrl') sfInstance = serverUrl.replace('http://', '').replace('https://', '').split('/')[0].replace('-api', '') return (sessionId, sfInstance)
def check_retrieve_status(self, async_process_id): """ After async process is done, post a checkRetrieveStatus to obtain the zipFile(base64) @async_process_id: retrieve request asyncProcessId """ server_url = globals()[ self.username]['instance_url'] + "/services/Soap/m/28.0" headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } soap_body = soap_bodies.check_retrieve_status_body.format( session_id=globals()[self.username]["session_id"], async_process_id=async_process_id) response = requests.post(server_url, soap_body, verify=False, headers=headers) # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString( content, "errorCode") result["message"] = getUniqueElementValueFromXmlString( content, "message") return result result["zipFile"] = getUniqueElementValueFromXmlString( content, "zipFile") return result
def check_job_status(job_id): url = globals()["instance_url"] + "/services/async/27.0/job/" + job_id headers = { "X-SFDC-Session": access_token } response = requests.get(url, data = None, verify = False, headers = headers) job_status = getUniqueElementValueFromXmlString(response.content, "state") while job_status != "Completed": print(job_id + " is not completed, please continue waiting...") time.sleep(15) check_job_status(job_id) return True
def create_job(sobject, operation): url = globals()["instance_url"] + "/services/async/27.0/job" body = soap_bodies.create_job.format(operation=operation, sobject=sobject) headers = { "X-SFDC-Session": globals()["access_token"], "Content-Type": "application/xml; charset=UTF-8", "Accept": "text/plain" } response = requests.post(url, body, verify = False, headers = headers) job_id = getUniqueElementValueFromXmlString(response.content, "id") if job_id == None: print(sobject + " is not valid sobject, please check.") return job_id
def retrieve_all(self): """ 1. Issue a retrieve request to start the asynchronous retrieval and asyncProcessId is returned 2. Thread sleep for a while and then issue a checkStatus request to check whether the async process job is completed. 3. After the job is completed, issue a checkRetrieveStatus request to obtain the zipFile(base64) in the retrieve result. 4. Use Python Lib base64 to convert the base64 string to zip file. 5. Use Python Lib zipFile to unzip the zip file to path """ # Firstly Login self.login(False) # 1. Issue a retrieve request to start the asynchronous retrieval server_url = globals()[ self.username]['instance_url'] + "/services/Soap/m/28.0" headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } # Populate the soap_body with actual session id soap_body = soap_bodies.retrieve_sobjects_workflow_task_body.format( session_id=globals()[self.username]["session_id"]) response = requests.post(server_url, soap_body, verify=False, headers=headers) # Check whether session_id is expired if "INVALID_SESSION_ID" in response.text: self.login(True) return self.retrieve_all() # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString( content, "errorCode") result["message"] = getUniqueElementValueFromXmlString( content, "message") self.result = result return # Get async process id async_process_id = getUniqueElementValueFromXmlString(content, "id") print("asyncProcessId: " + async_process_id) # 2. issue a check status loop request to assure the async # process is done result = self.check_status(async_process_id) # If check status request failed, this will not be done print(result) if result["done"] == "Failed": self.result = result return # 3 Obtain zipFile(base64) print("Downloading zipFile in this retrieve result...") result = self.check_retrieve_status(async_process_id) self.result = result
def execute_anonymous(self, apex_string): """ Generate a new view to display executed reusult of Apex Snippet :apex_string: Apex Snippet """ # Firstly Login self.login(False) server_url = globals()[ self.username]['instance_url'] + "/services/Soap/s/28.0" # https://gist.github.com/richardvanhook/1245068 headers = { "Content-Type": "text/xml;charset=UTF-8", "SOAPAction": '""' } # If we don't quote <, >, & in body, we will get below exception # Element type "String" must be followed by either attribute specifications, ">" or "/>" # http://wiki.python.org/moin/EscapingXml apex_string = quoteattr(apex_string).replace('"', '') soap_body = soap_bodies.execute_anonymous_body.format( session_id=globals()[self.username]["session_id"], apex_string=apex_string) response = requests.post(server_url, soap_body, verify=False, headers=headers) # Check whether session_id is expired if "INVALID_SESSION_ID" in response.text: self.login(True) return self.execute_anonymous(apex_string) # If status_code is > 399, which means it has error content = response.content result = {"status_code": response.status_code} if response.status_code > 399: result["errorCode"] = getUniqueElementValueFromXmlString( content, "errorCode") result["message"] = getUniqueElementValueFromXmlString( content, "message") self.result = result return result # If execute anonymous succeed, just display message with a new view result["debugLog"] = unescape( getUniqueElementValueFromXmlString(content, "debugLog")) result["column"] = getUniqueElementValueFromXmlString( content, "column") result["compileProblem"] = unescape( getUniqueElementValueFromXmlString(content, "compileProblem")) result["compiled"] = getUniqueElementValueFromXmlString( content, "compiled") result["line"] = getUniqueElementValueFromXmlString(content, "line") result["success"] = getUniqueElementValueFromXmlString( content, "success") pprint.pprint(result) # Self.result is used to keep thread result self.result = result # This result is used for invoker return result