Using actix-web's web::Bytes, I can get the payload from a form submission. It is a simple form with one input named username and another input named text. The raw bytes stream looks like this
b"username=User&text=%22Hello%2C+World%21%22"
The content in the text submitted is simply "Hello, World!".
Without using serde, what methods can I use to convert the above %22Hello%2C+World%21%22 into the intended string "Hello, World!"?
Your data is encoded as application/x-www-form-urlencoded. you can use a crate like form-urlencoded to parse it.
Example:
let x = form_urlencoded::parse("%23first=%25try%25");
println!("{:?}", x); // [("#first", "%try%")]
Desired Behaviour
I am trying to get the file properties of a file uploaded via a Microsoft Form in Power Automate.
Research
I've tried numerous variations of suggestions from sources such as:
How to get data from JSON objects using expressions in Power Automate (video)
Working with files from the Forms "File Upload" question type
Reference guide to using functions in expressions for Azure Logic Apps and Power Automate
I am a fairly experienced developer and I am familiar with variable types (String, Array, Object etc) and how to reference items in an object with dot or bracket notation and accessing array items by index.
I'm also familiar with:
JSON.parse()
The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string.
JSON.stringify()
The JSON.stringify() method converts a JavaScript object or value to a JSON string
And have read about Power Automate's Parse JSON action
To reference or access properties in JavaScript Object Notation (JSON) content, you can create user-friendly fields or tokens for those properties by using the Parse JSON action. That way, you can select those properties from the dynamic content list when you specify inputs for your logic app. For this action, you can either provide a JSON schema or generate a JSON schema from your sample JSON content or payload
But I am still having a lot of difficulty getting the values I need.
What I've Tried
01) Use Parse JSON to access properties of the Reponse body:
02) Run the flow and look at the Raw Outputs of Parse JSON:
{
"body": {
"responder": "me#domain.com",
"submitDate": "7/5/2021 7:03:26 AM",
"letters-and-numbers-here-1": "some text here",
"letters-and-numbers-here-2": "[{\"name\":\"File 01 Name.docx\",\"link\":\"https://tenant.sharepoint.com/sites/MySiteName/_layouts/15/Doc.aspx?sourcedoc=%7Bletters-and-numbers%7D&file=File%2001%20Name%20_Uploader%20Name.docx&action=default&mobileredirect=true\",\"id\":\"id-is-here\",\"type\":null,\"size\":20411,\"referenceId\":\"reference-id-is-here\",\"driveId\":\"drive-id-is-here\",\"status\":1,\"uploadSessionUrl\":null}]",
"letters-and-numbers-here-3": "[{\"name\":\"File 02 Name.docx\",\"link\":\"https://tenant.sharepoint.com/sites/MySiteName/_layouts/15/Doc.aspx?sourcedoc=%7Bletters-and-numbers%7D&file=File%2002%20Name%20_Uploader%20Name.docx&action=default&mobileredirect=true\",\"id\":\"id-is-here\",\"type\":null,\"size\":20411,\"referenceId\":\"reference-id-is-here\",\"driveId\":\"drive-id-is-here\",\"status\":1,\"uploadSessionUrl\":null}]",
"letters-and-numbers-here-4": "some other text here"
}
}
03. Try and get the name value of the first File Upload field.
I had assumed that the first Parse JSON would have recursively set all values as JSON Objects, however it looks like the value of the File Upload field is still a string. So I figure I have to do another Parse JSON action on the File Upload field.
Content:
body('Parse_JSON')?['letters-and-numbers-here-2']
Sample JSON Payload:
{
"letters-and-numbers-here-2": "[{\"name\":\"File 01 Name.docx\",\"link\":\"https://tenant.sharepoint.com/sites/MySiteName/_layouts/15/Doc.aspx?sourcedoc=%7Bletters-and-numbers%7D&file=File%2001%20Name%20_Uploader%20Name.docx&action=default&mobileredirect=true\",\"id\":\"id-is-here\",\"type\":null,\"size\":20411,\"referenceId\":\"reference-id-is-here\",\"driveId\":\"drive-id-is-here\",\"status\":1,\"uploadSessionUrl\":null}]"
}
Which produces the Error:
[
{
"message": "Invalid type. Expected Object but got Array.",
"lineNumber": 0,
"linePosition": 0,
"path": "",
"schemaId": "#",
"errorType": "type",
"childErrors": []
}
]
So I tried to target the first Object within the File Upload field Array, and I try the following values as the Content of Parse JSON 2:
body('Parse_JSON')?['letters-and-numbers-here-2']?[0]
body('Parse_JSON')['letters-and-numbers-here-2'][0]
Both produce the error:
Unable to process template language expressions in action 'Parse_JSON_2' inputs at line '1' and column '9206': 'The template language expression 'body('Parse_JSON')['letters-and-numbers-here-2'][0]' cannot be evaluated because property '0' cannot be selected. Property selection is not supported on values of type 'String'. Please see https://aka.ms/logicexpressions for usage details.'
Question
How do I access the File Upload field properties?
For reference, the Microsoft Form has 4 fields of type:
Text
File Upload (limited to 1 file only)
File Upload (limited to 1 file only)
Choice
The connectors used are:
When a new response is submitted
Get response details
The body returned by Get response details, in Raw outputs, is:
"body": {
"responder": "me#domain.com",
"submitDate": "7/5/2021 3:17:56 AM",
"lots-of-letters-and-numbers-1": "text string here",
"lots-of-letters-and-numbers-2": [{.....}],
"lots-of-letters-and-numbers-3": [{.....}],
"lots-of-letters-and-numbers-4": "text string here"
}
I tried a different approach, without the Parse JSON action, and could access the file name:
The expression values were:
`Compose` > `Inputs`: json(body('Get_response_details')?['lots-of-letters-and-numbers-2'])
`Initialize Variable` > `Value`: outputs('Compose')[0]['name']
Or, even simpler, just using Compose:
Or Initialize variable:
Using this expression with json() and body():
json(body('Get_response_details')?['lots-of-letters-and-numbers-2'])[0]['name']
I'm not sure if this is the best approach or if it comes with any 'gotchas'.
It is not possible to correctly transfer the Cyrillic alphabet to the post request. Letters are replaced with question marks.
Everything works well with numbers and the Latin alphabet.
name = 'иии.docx'
multipartRequestEntity.addPart('filename', new StringBody(name)) // return '???.docx'
name = 'fff.docx'
multipartRequestEntity.addPart('filename', new StringBody(name)) // return 'fff.docx'
How to correctly pass the Cyrillic alphabet in a post request?
Try by create the String with encoding, something like this:
name = new String('иии.docx', 'UTF-8')
Also, verify if the multipartRequestEntity has any method to set the encoding on the output.
My PayPal IPNs are validating fine, except for those with a txn_type of recurring_payment. When I pass the message to the validation endpoint, I'm converting the body into a query string using
var verificationString = '?cmd=_notify-validate';
Object.keys(body).map((key) => {
verificationString = verificationString + '&' + key + '=' + body[key];
return key;
});
My best guess is that this is messing with the order of the properties. PayPal's documentation states:
Your listener HTTPS POSTs the complete, unaltered message back to PayPal; the message must contain the same fields (in the same order) as the original message and be encoded in the same way as the original message.
But I didn't think Object.keys(body).map would rearrange anything in Nodejs. Any suggestions?
Found the solution. Turns out that PayPal allows user fields to contain things like backslash, newline characters, etc. This specific IPN had an address field with a \r\n newline between the street and apartment number. Using my original code, this was somehow being encoded different.
Instead of assembling the query string like in my original question, I now assemble it like this, since it preserves all characters and encoding:
var verificationString = '?cmd=_notify-validate&' + request.rawBody.toString();
And that solved the problem!
How can I reliably get the 64bit data from an XML file to a byte[] and then compare that with a string? The following code fails as it seems the whitespace is causing the assert to fail. The goal is for the assert to pass.
Note that it is important that we have it in the form of byte[] at somepoint, but not that the comparison be via strings
<Contents>VGVzdGluZyBURSBzZXNzaW9uIGNvbnRhaW5pbmcgQ29tcGxldGUgUGVyc29uIEEgYW5kIENvbXBs
ZXRlIEVxdWlwbWVudCBCLg0KDQpUZXN0IFRlc3QNCg0KUmVmZXJlbmNlcyBDb21wbGV0ZSBQbGFj
ZSBB
</Contents>
byte[] byteData = document.Contents.text()
assert 'VGVzdGluZyBURSBzZXNzaW9uIGNvbnRhaW5pbmcgQ29tcGxldGUgUGVyc29uIEEgYW5kIENvbXBs'+
'ZXRlIEVxdWlwbWVudCBCLg0KDQpUZXN0IFRlc3QNCg0KUmVmZXJlbmNlcyBDb21wbGV0ZSBQbGFj'+
'ZSBB' == new String(byteData)
Base 64 data is a special encoding of text to ASCII to be URL friendly (historically)
EDIT thanks to comment below, actually base64 was to encode data to send via for email
to extract text from your data, do this:
new String(
'VGVzdGluZyBURSBzZXNzaW9uIGNvbnRhaW5pbmcgQ29tcGxldGUgUGVyc29uIEEgYW5kIENvbXBsZXRlIEVxdWlwbWVudCBCLg0KDQpUZXN0IFRlc3QNCg0KUmVmZXJlbmNlcyBDb21wbGV0ZSBQbGFjZSBB')
.decodeBase64()
)
result starts with 'ession containing Complete Person A and Complete Equipment B.'
from http://mrhaki.blogspot.fr/2009/11/groovy-goodness-base64-encoding.html