def testToken(): try: if(ds_config("DS_CLIENT_ID") == "{CLIENT_ID}"): print(date() + "Problem: you need to configure this example, either via environment variables (recommended)\n" "or via the ds_configuration.js file.\n" "See the README file for more information\n") check_token() # An API problem except docusign.ApiException as e: print("\n\nDocuSign Exception!") # Special handling for consent_required body = e.body.decode('utf8') if("consent_required" in body): consent_scopes = "signature%20impersonation" consent_redirect_URL = "https://www.docusign.com" consent_url = "{}/oauth/auth?response_type=code&scope={}&client_id={}&redirect_uri={}".format(ds_config("DS_AUTH_SERVER"), consent_scopes, ds_config("DS_CLIENT_ID"),consent_redirect_URL) print(f"""\nC O N S E N T R E Q U I R E D Ask the user who will be impersonated to run the following url: {consent_url} It will ask the user to login and to approve access by your application. Alternatively, an Administrator can use Organization Administration to pre-approve one or more users.""") sys.exit(0) else: # Some other DocuSign API problem print (f" Reason: {e.reason}") print (f" Error response: {e.body.decode('utf8')}") sys.exit(0) # Not an API problem except Exception as e: print(date() + e)
def saveDoc(envelopeId, orderNumber): try: # api_client object created when checkToken() function was called in aws_worker api_client.set_default_header("Authorization", "Bearer " + api_client.token) accountID = get_account_id() envelope_api = EnvelopesApi(api_client) results_file = envelope_api.get_document(accountID , "combined" , envelopeId) # Create the output directory if needed output_directory = os.path.join(current_directory, r'output') if not os.path.exists(output_directory): os.makedirs(output_directory) if(not os.path.exists(output_directory)): print(date() + "Failed to create directory") filePath = os.path.join(current_directory, "output", ds_config("OUTPUT_FILE_PREFIX") + orderNumber + ".pdf") # Cannot create a file when file with the same name already exists if(os.path.exists(filePath)): # Remove the existing file os.remove(filePath) # Save the results file in the output directory and change the name of the file os.rename(results_file,filePath) # Create a file except ApiException as e: print(date() + "API exception: {}. saveDoc error".format(e)) # Catch exception while fetching and saving docs for envelope except Exception as e: print(date() + "Error while fetching and saving docs for envelope {}, order {}".format(envelopeId, orderNumber)) print(date() + "saveDoc error {}".format(e))
def processTest(test): # Exit the program if BREAK_TEST equals to true or if orderNumber contains "/break" if(ds_config("ENABLE_BREAK_TEST") == "True" and "/break" in ("" + test)): print(date() +"BREAKING worker test!") sys.exit(2) print(date() + "Processing test value {}".format(test)) # Create the test directory if needed test_directory = os.path.join(current_directory, r'test_messages') if not os.path.exists(test_directory): os.makedirs(test_directory) if(not os.path.exists(test_directory)): print(date() + "Failed to create directory") # First shuffle test1 to test2 (if it exists) and so on for i in range(9,0,-1): old_File_path = os.path.join(test_directory, "test" + str(i) + ".txt") new_File_path = os.path.join(test_directory, "test" + str(i+1) + ".txt") # If the old file exists if(os.path.exists(old_File_path)): # If the new file exists - remove it if(os.path.exists(new_File_path)): os.remove(new_File_path) # Rename the file name - only works if new_File_path does not exist os.rename(old_File_path, new_File_path) # The new test message will be placed in test1 - creating new file newFile= open(os.path.join(test_directory, "test1.txt"), "w+") newFile.write(test) print(date() + "New file created") newFile.close
def startQueue(): # Maintain the array checkLogQ as a FIFO buffer with length 4. # When a new entry is added, remove oldest entry and shuffle. def addCheckLogQ(message): length = 4 # If checkLogQ size is smaller than 4 add the message if(checkLogQ.qsize() < length): checkLogQ.put(message) # If checkLogQ size is bigger than 4 else: # Remove the oldest message and add the new one checkLogQ.get() checkLogQ.put(message) # Prints all checkLogQ messages to the console def printCheckLogQ(): # Prints and Deletes all the elements in the checkLogQ for index in range(checkLogQ.qsize()): print(checkLogQ.get()) try: while(True): # Receive messages from queue, maximum waits for 20 seconds for message # receive_request - contain all the queue messages receive_request = (sqs.receive_message(QueueUrl=ds_config("QUEUE_URL"), WaitTimeSeconds=20, MaxNumberOfMessages=10)).get("Messages") addCheckLogQ(date() +"Awaiting a message...") # If receive_request is not None (when message is received) if(receive_request is not None): msgCount = len(receive_request) else: msgCount=0 addCheckLogQ(date() +"found {} message(s)".format(msgCount)) # If at least one message has been received if(msgCount): printCheckLogQ() for message in receive_request: messageHandler(message) # Catches all types of errors that may occur during the program except Exception as e: printCheckLogQ() print(date() + "Queue receive error: {}".format(e)) time.sleep(5) # Restart the program global restart restart = True
def test_send(cls): try: print(date() + "Starting\n") print( "Sending an envelope. The envelope includes HTML, Word, and PDF documents.\n" + "It takes about 15 seconds for DocuSign to process the envelope request..." ) result = send_envelope() print( f"Envelope status: {result.status}. Envelope ID: {result.envelope_id}" ) SaveEnvelope.created() print(date() + "Done\n") except IOError as e: print(f"Could not open the file: {e}") except docusign.ApiException as e: print("DocuSign Exception!")
def listenForever(): # Check that we can get a DocuSign token testToken() while(True): global restart if(restart): print(date() + "Starting queue worker") restart = False # Start the queue worker startQueue() time.sleep(5)
def messageHandler(message): if(ds_config("DEBUG") == "True"): print(date() + "Processing message id: {}".format(message["MessageId"])) try: # Creates a Json object from the message body body = json.loads(message["Body"]) except Exception as e: body = False if(body): # Parse the information from message body. the information contains contains fields like test and xml test = body["test"] xml = body["xml"] process(test, xml) else: print(date() + "Null or bad body in message id {}. Ignoring.".format(message["MessageId"])) # Delete received message from queue sqs.delete_message(QueueUrl=ds_config("QUEUE_URL"),ReceiptHandle=message["ReceiptHandle"])
def process(test, xml): # Guarding against injection attacks # Check the incoming test variable to ensure that it ONLY contains the expected data (empty string "", "/break" or integers string) # matcher equals true when it finds wrong input pattern = "[^0-9]" matcher = re.search(pattern, test) validInput = test == "" or test == "/break" or not matcher if(validInput): if(not test == ""): # Message from test mode processTest(test) else: print(date() +"Wrong test value: {}".format(test)) print("test can only be: /break, empty string or integers string") # In test mode there is no xml sting, should be checked before trying to parse it if(not xml == ""): # Step 1. parse the xml root = ET.fromstring(xml) # get the namespace from the xml def get_namespace(element): ns = re.match(r'\{.*\}', element.tag) return ns.group(0) if ns else '' nameSpace = get_namespace(root) # Extract from the XML the fields values envelopeId = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}EnvelopeID').text subject = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}Subject').text senderName = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}UserName').text senderEmail = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}Email').text status = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}Status').text created = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}Created').text orderNumber = root.find(f'{nameSpace}EnvelopeStatus/{nameSpace}CustomFields/{nameSpace}CustomField/{nameSpace}Value').text if(status == "Completed"): completedMsg = "Completed: True" else: completedMsg = "" # For debugging, you can print the entire notification print("EnvelopeId: {}".format(envelopeId)) print("Subject: {}".format(subject)) print("Sender: {}, {}".format(senderName, senderEmail)) print("Order Number: {}".format(orderNumber)) print("Status: {}".format(status)) print("Sent: {}, {}".format(created, completedMsg)) # Step 2. Filter the notifications ignore = False # Guarding against injection attacks # Check the incoming orderNumber variable to ensure that it ONLY contains the expected data ("Test_Mode" or integers string) # Envelope might not have Custom field when orderNumber == None # matcher equals true when it finds wrong input matcher = re.search(pattern, orderNumber) validInput = orderNumber == "Test_Mode" or orderNumber == None or not matcher if(validInput): # Check if the envelope was sent from the test mode # If sent from test mode - ok to continue even if the status not equals to Completed if(not orderNumber == "Test_Mode"): if(not status == "Completed"): ignore = True if(ds_config("DEBUG") == "True"): print(date() +"IGNORED: envelope status is {}".format(status)) if(orderNumber == None or orderNumber == ""): ignore = True if(ds_config("DEBUG") == "True"): print(date() +"IGNORED: envelope does not have a {} envelope custom field.".format(ds_config("ENVELOPE_CUSTOM_FIELD"))) else: ignore = True print(date() + "Wrong orderNumber value: {}".format(orderNumber)) print("orderNumber can only be: Test_Mode or integers string") # Step 3. (Future) Check that this is not a duplicate notification # The queuing system delivers on an "at least once" basis. So there is a # chance that we have already processes this notification. # # For this example, we'll just repeat the document fetch if it is duplicate notification # Step 4 save the document - it can raise an exception which will be caught at startQueue if(not ignore): saveDoc(envelopeId, orderNumber)
def test_run(cls): for index in range(8): RunTest.timeChecks.append(datetime.now() + timedelta(hours=index+1)) print(date() + "Starting") RunTest.doTests() print(date() + "Done")