Example #1
0
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
Example #4
0
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!")
Example #6
0
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)    
Example #7
0
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")