Web Addin Outlook - javascript
I am developing a new web addin for Outlook using EWS and JavaScript. The scope is to get the current email selected and add it to a new email as attachement. Following the instructions found here: https://msdn.microsoft.com/en-us/library/office/dn726694(v=exchg.150).aspx#bk_createattachews -> I have created some functions to do those steps explained in the MSDN documentation. The problem is that I don't get any errors or something that can tell me what I am doing wrong. Here is my Code:
function soapToForwardItemCallback(asyncResult) {
var parser;
var xmlDoc;
if (asyncResult.error != null) {
app.showNotification("EWS Status", asyncResult.error.message);
}
else {
var response = asyncResult.value;
if (window.DOMParser) {
parser = new DOMParser();
xmlDoc = parser.parseFromString(response, "text/xml");
}
else // Older Versions of Internet Explorer
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(response);
}
// Get the required response, and if it's NoError then all has succeeded, so tell the user.
// Otherwise, tell them what the problem was. (E.G. Recipient email addresses might have been
// entered incorrectly --- try it and see for yourself what happens!!)
var result = xmlDoc.getElementsByTagName("m:ResponseCode")[0].textContent;
if (result == "NoError") {
app.showNotification("EWS Status", "Success!");
}
else {
app.showNotification("EWS Status", "The following error code was recieved: " + result);
}
}
}
function getCurrentEmail() {
var item = Office.context.mailbox.item;
item_id = item.itemId;
var getMimeContent = '<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
'xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
// ' <soap:Header>' +
// ' <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
// ' </soap:Header>' +
'<soap:Body>' +
'<m:GetItem>' +
// ' xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"' +
// ' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
'<m:ItemShape>' +
'<t:BaseShape>IdOnly</t:BaseShape>' +
'<t:AdditionalProperties>' +
'<t:FieldURI FieldURI="item:MimeContent" />' +
'<t:FieldURI FieldURI="item:Subject" />' +
'</t:AdditionalProperties>' +
'</m:ItemShape>' +
'<m:ItemIds>' +
'<t:ItemId Id="' + item_id + '"/>' +
'</m:ItemIds>' +
'</m:GetItem>' +
'</soap:Body>' +
'</soap:Envelope>'
mailbox.makeEwsRequestAsync(getMimeContent, createMail);
}
function createMail(asyncResult) {
var parser = new DOMParser();
var xmlDoc;
if (asyncResult.error !== null) {
app.showNotification("EWS Status", asyncResult.error.message);
}
else {
var response = asyncResult.value;
if (window.DOMParser) {
xmlDoc = parser.parseFromString(response, "text/xml");
}
else // Older Versions of Internet Explorer
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(response);
}
var toAddresses = 'alexandru.banica#rodacsoft.ro';
var addressesSoap = "";
addressesSoap += "<t:Mailbox><t:EmailAddress>" + toAddresses + "</t:EmailAddress></t:Mailbox>";
var soapToCreateNewEmail = '<?xml version="1.0" encoding="utf-8"?>'+
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'+
'xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"'+
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"'+
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'+
' <soap:Header>'+
' <t:RequestServerVersion Version="Exchange2013" />'+
' </soap:Header>'+
' <soap:Body>'+
' <m:CreateItem MessageDisposition="SaveOnly">'+
' <m:Items>'+
' <t:Message>'+
' <t:Subject>Message with Item Attachment (MimeContent)</t:Subject>'+
' <t:Body BodyType="HTML">The attachmen</t:Body>'+
' <t:ToRecipients>'+ addressesSoap
+
' </t:ToRecipients>'+
' </t:Message>'+
' </m:Items>'+
' </m:CreateItem>'+
' </soap:Body>'+
' </soap:Envelope>'
mailbox.makeEwsRequestAsync(soapToCreateNewEmail,soapToGetItemDataCallback);
}
}
function createAttachement(asyncResult) {
var parser = new DOMParser();
var xmlDoc;
if (asyncResult.error !== null) {
app.showNotification("EWS Status", asyncResult.error.message);
}
else {
var response = asyncResult.value;
if (window.DOMParser) {
xmlDoc = parser.parseFromString(response, "text/xml");
}
else // Older Versions of Internet Explorer
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(response);
}
var mimeTag = xmlDoc.getElementsByTagName("t:MimeContent")[0].innerText;
var soapToCreateAttachement = '<?xml version="1.0" encoding="utf-8"?>'+
' <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'+
' xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"'+
' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"'+
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'+
' <soap:Header>'+
' <t:RequestServerVersion Version="Exchange2013" />'+
' </soap:Header>'+
' <soap:Body>'+
' <m:CreateAttachment>'+
' <m:ParentItemId Id="'+item_id+'" />'+
' <m:Attachments>'+
' <t:ItemAttachment>'+
' <t:Name>Play tennis?</t:Name>'+
' <t:IsInline>false</t:IsInline>'+
' <t:Message>'+
' <t:MimeContent CharacterSet="UTF-8">'+ mimeTag +'</t:MimeContent>'+
' </t:Message>'+
' </t:ItemAttachment>'+
' </m:Attachments>'+
' </m:CreateAttachment>'+
' </soap:Body>'+
' </soap:Envelope>'
mailbox.makeEwsRequestAsync(soapToCreateAttachement,sendEmailAsAttachement);
}
}
function sendEmailAsAttachement(asyncResult) {
var parser = new DOMParser();
var xmlDoc;
if (asyncResult.error !== null) {
app.showNotification("EWS Status", asyncResult.error.message);
}
else {
var response = asyncResult.value;
if (window.DOMParser) {
xmlDoc = parser.parseFromString(response, "text/xml");
}
else // Older Versions of Internet Explorer
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(response);
}
var changeKey = xmlDoc.getElementsByTagName("t:ItemId")[0].getAttribute("ChangeKey");
var soapToSendEmailAttachment = ' <?xml version="1.0" encoding="utf-8"?>' +
' <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
' xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"' +
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
' <soap:Header>' +
' <t:RequestServerVersion Version="Exchange2013" />' +
' </soap:Header>' +
' <soap:Body>' +
' <m:SendItem SaveItemToFolder="true">' +
' <m:ItemIds>' +
' <t:ItemId Id="'+ item_id +'"' +
' ChangeKey="'+ changeKey +'" />' +
' </m:ItemIds>' +
' <m:SavedItemFolderId>' +
' <t:DistinguishedFolderId Id="sentitems" />' +
' </m:SavedItemFolderId>' +
' </m:SendItem>' +
' </soap:Body>' +
' </soap:Envelope>'
mailbox.makeEwsRequestAsync(soapToSendEmailAttachment, soapToForwardItemCallback);
}
}
The first function called on button click is getCurrentEmail(). I am not sure if I can do the SOAP calls like that. Any help would be greatly appreciated! Please tell me if you need additional information. Thank you!
I am not sure if I can do the SOAP calls like that.
The following resource describes EWS operations that add-ins support. "m:CreateAttachment" is not one of them; probably you should start from there.
EDIT:
I don't understand how comes you don't get any errors. Are you debugging? Can you hit break point? Well this is all weird.
Now let me tell you what I've done and what issues with your code I noticed ...
I created the simple project and added your code. I called "getCurrentEmail()" function and work just with this function. I didn't verify any other function, because I believe you should do this on your own.
Javascript errors: If you use "strict" JS mode (and you should!) the function has "item_id" variable which is not defined as "var". You should make it local by using "var" keyword. Next when you call "mailbox.makeEwsRequestAsync" the "mailbox" variable is undefined as well. you should call it as "Office.context.mailbox.makeEwsRequestAsync".
EWS request is not properly formed at all. I don't know, may be you played with it, but the example EWS XML from the resource you have provided is different than you are creating by inserting message Id. When I fixed JS errors (look at the point 2 above) and send EWS request it returned starts "Error" and proper description that request is misformed. I have changed the request to match the request provided in example and it returns "success" and information you have requested, as of subject and MIME content.
I will share my code just for the function you have asked and the rest try to do on your own. Here you go ...
function _wrapSoapEnvelope(payload) {
var result = '<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' +
'xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" ' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
'<soap:Header>' +
'<t:RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
'</soap:Header>' +
'<soap:Body>' + payload + '</soap:Body>' +
'</soap:Envelope>';
return result;
};
function getCurrentEmail() {
var item = Office.context.mailbox.item,
item_id = item.itemId;
var getMimeContent = '<m:GetItem>' +
'<m:ItemShape>' +
'<t:BaseShape>IdOnly</t:BaseShape>' +
'<t:AdditionalProperties>' +
'<t:FieldURI FieldURI="item:MimeContent" />' +
'<t:FieldURI FieldURI="item:Subject" />' +
'</t:AdditionalProperties>' +
'</m:ItemShape>' +
'<m:ItemIds>' +
'<t:ItemId Id="' + item_id + '"/>' +
'</m:ItemIds>' +
'</m:GetItem>'
Office.context.mailbox.makeEwsRequestAsync(_wrapSoapEnvelope(getMimeContent), createMail);
}
Related
EWS CreateItem give 2 emails messages in drafts
I need to create an email, attach another email message to it and save it into drafts folder; To proceed, I use first GetItem, then CreateItem. But each time it appears 2 email messages in that folder. Each email message contains the attachment and is in draft mode. I don't understand why there is 2 email messages. Please help me. Thank you. Here is my code: (function () { "use strict"; Office.initialize = function (reason) { $(document).ready(function () { app.initialize(); $('#fowardToGroups').click(function () { sendNow(); }); }); }; var item_id; var mailbox; async function sendNow() { var item = Office.context.mailbox.item; item_id = item.itemId; mailbox = Office.context.mailbox; var receiver="test#ymail.com"; var soapToCreateItem='<?xml version="1.0" encoding="utf-8"?>'+ ' <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'+ ' xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"'+ ' xmlns:xsd="http://www.w3.org/2001/XMLSchema"' + ' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"'+ ' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'+ ' <soap:Header>'+ ' <t:RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />'+ ' </soap:Header>'+ ' <soap:Body>'+ ' <m:CreateItem MessageDisposition="SaveOnly">'+ ' <m:SavedItemFolderId> '+ ' <t:DistinguishedFolderId Id="drafts" /> '+ ' </m:SavedItemFolderId> '+ ' <m:Items>'+ ' <t:Message>'+ ' <t:Subject>Suspicious e-mail </t:Subject>'+ ' <t:Body BodyType="HTML">body</t:Body>'+ ' <t:ToRecipients>'+ ' <t:Mailbox>'+ ' <t:EmailAddress>'+receiver+'</t:EmailAddress>'+ ' </t:Mailbox>'+ ' </t:ToRecipients>'+ ' </t:Message>'+ ' </m:Items>'+ ' </m:CreateItem>'+ ' </soap:Body>'+ ' </soap:Envelope>'; mailbox.makeEwsRequestAsync(soapToCreateItem, soapToCreateItemCallback); } function soapToCreateItemCallback(asyncResult) { var parser; var xmlDoc; if (asyncResult.error != null) { app.showNotification("EWS Status 1", asyncResult.error.message); } else { var response = asyncResult.value; if (window.DOMParser) { parser = new DOMParser(); xmlDoc = parser.parseFromString(response, "text/xml"); } else // Older Versions of Internet Explorer { xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.loadXML(response); } var result = xmlDoc.getElementsByTagName("m:ResponseCode")[0].textContent; if (result == "NoError") { app.showNotification("Status", "Success !"); } else { app.showNotification("Status", "error : " + result); } } } })();
Use variable from callback as global variable
I made a block in which the request to the specified URL occurs. Inside this block, I can work with the data from response, but outside this block I can not get this data because of asynchrony. Is it possible to simulate a synchronous request in blockly or in some other way, save the received data to a global variable? code of the created block: Blockly.Blocks['request'] = '<block type="request">' + ' <value name="URL">' + ' <shadow type="text">' + ' <field name="TEXT">text</field>' + ' </shadow>' + ' </value>' + ' <value name="LOG">' + ' </value>' + ' <value name="WITH_STATEMENT">' + ' </value>' + ' <mutation with_statement="false"></mutation>' + '</block>'; Blockly.Blocks['request'] = { init: function() { this.appendDummyInput('TEXT') .appendField('request'); this.appendValueInput('URL') .appendField('URL'); this.appendDummyInput('WITH_STATEMENT') .appendField('with results') .appendField(new Blockly.FieldCheckbox('FALSE', function (option) { var delayInput = (option == true); this.sourceBlock_.updateShape_(delayInput); }), 'WITH_STATEMENT'); this.appendDummyInput('LOG') .appendField('log level') .appendField(new Blockly.FieldDropdown([ ['none', ''], ['info', 'log'], ['debug', 'debug'], ['warning', 'warn'], ['error', 'error'] ]), 'LOG'); this.setInputsInline(false); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(230); this.setTooltip('Request URL'); this.setHelpUrl('https://github.com/request/request'); }, mutationToDom: function() { var container = document.createElement('mutation'); container.setAttribute('with_statement', this.getFieldValue('WITH_STATEMENT') === 'TRUE'); return container; }, domToMutation: function(xmlElement) { this.updateShape_(xmlElement.getAttribute('with_statement') == 'true'); }, updateShape_: function(withStatement) { // Add or remove a statement Input. var inputExists = this.getInput('STATEMENT'); if (withStatement) { if (!inputExists) { this.appendStatementInput('STATEMENT'); } } else if (inputExists) { this.removeInput('STATEMENT'); } }}; Blockly.JavaScript['request'] = function(block) { var logLevel = block.getFieldValue('LOG'); var URL = Blockly.JavaScript.valueToCode(block, 'URL', Blockly.JavaScript.ORDER_ATOMIC); var withStatement = block.getFieldValue('WITH_STATEMENT'); var logText; if (logLevel) { logText = 'console.' + logLevel + '("request: " + ' + URL + ');\n' } else { logText = ''; } if (withStatement === 'TRUE') { var statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT'); if (statement) { var xmlhttp = "var xmlHttp = new XMLHttpRequest();"; var xmlopen = "xmlHttp.open('POST', " + URL + ", true);"; var xmlheaders = "xmlHttp.setRequestHeader('Content-type', 'application/json');\n" + "xmlHttp.setRequestHeader('Authorization', 'Bearer psokmCxKjfhk7qHLeYd1');"; var xmlonload = "xmlHttp.onload = function() {\n" + " console.log('recieved:' + this.response);\n" + " var response = this.response;\n" + " var brightness = 'brightness: ' + JSON.parse(this.response).payload.devices[0].brightness;\n" + " " + statement + "\n" + "}"; var json = JSON.stringify({ "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf", "inputs": [{ "intent": "action.devices.QUERY", "payload": { "devices": [{ "id": "0", "customData": { "smartHomeProviderId": "FkldJVJCmDNSaoLkoq0txiz8Byf2Hr" } }] } }] }); var xmlsend = "xmlHttp.send('" + json + "');"; var code = xmlhttp + '\n' + xmlopen + '\n' + xmlheaders + '\n' + xmlonload + '\n' + xmlsend; return code; } else { var xmlhttp = "var xmlHttp = new XMLHttpRequest();"; var xmlopen = "xmlHttp.open('POST', " + URL + ", true);"; var xmlheaders = "xmlHttp.setRequestHeader('Content-type', 'application/json');\n" + "xmlHttp.setRequestHeader('Authorization', 'Bearer psokmCxKjfhk7qHLeYd1');"; var xmlonload = "xmlHttp.onload = function() {\n" + " console.log('recieved:' + this.response);\n" + "}"; var json = JSON.stringify({ "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf", "inputs": [{ "intent": "action.devices.QUERY", "payload": { "devices": [{ "id": "0", "customData": { "smartHomeProviderId": "FkldJVJCmDNSaoLkoq0txiz8Byf2Hr" } }] } }] }); var xmlsend = "xmlHttp.send('" + json + "');"; var code = xmlhttp + '\n' + xmlopen + '\n' + xmlheaders + '\n' + xmlonload + '\n' + xmlsend; return code; } } else { var xmlhttp = "var xmlHttp = new XMLHttpRequest();"; var xmlopen = "xmlHttp.open('POST', " + URL + ", true);"; var xmlheaders = "xmlHttp.setRequestHeader('Content-type', 'application/json');\n" + "xmlHttp.setRequestHeader('Authorization', 'Bearer psokmCxKjfhk7qHLeYd1');"; var xmlonload = "xmlHttp.onload = function() {\n" + " console.log('recieved:' + this.response);\n" + "}"; var json = JSON.stringify({ "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf", "inputs": [{ "intent": "action.devices.QUERY", "payload": { "devices": [{ "id": "0", "customData": { "smartHomeProviderId": "FkldJVJCmDNSaoLkoq0txiz8Byf2Hr" } }] } }] }); var xmlsend = "xmlHttp.send('" + json + "');"; var code = xmlhttp + '\n' + xmlopen + '\n' + xmlheaders + '\n' + xmlonload + '\n' + xmlsend; return code; }};
We actually use Promises extensively in our Blockly environment. My suggestion would be to Promisify this and then use a generator function. For example, we use the co library to wrap our generated code, then use yield statements for asynchronous values to make them behave synchronously. For example: For a block setup similar to this -- The generated code would be something like this (simplified) -- co(function* () { var getUsername; // getFieldValue makes an asynchronous call to our database getUsername = (yield getFieldValue("username", "my user record Id", "users")); Promise.all(inputPromises) let inputPromises = []; inputPromises.push('User name is'); inputPromises.push(getUsername); yield new Promise(function(resolve, reject) { Promise.all(inputPromises).then(function(inputResults) { let [TITLE, MESSAGE] = inputResults; let activity = "toastMessage"; let LEVEL = "success"; try { var params = {message: MESSAGE, title: TITLE, level: LEVEL}; interface.notification(params); return resolve(); } catch(err) { return reject(err); } }).catch(reject); }); return true; } As you may have noticed, though, this isn't always as easy as just sticking a "yield" before the block. Depending on your setup, you may have to get more creative using Promise.all to get values in your block, etc. (We actually wound up editing a bunch of the Blockly core blocks to append 'yield' in front of inputs which had a "promise" type set amongst their output types in order to make this work, but based on your setup, this may be overkill.) Obviously, you would need to make sure this was either transpiled or run in an environment which supports ES6. Of course, once you enter an asynchronous setup, there's not really any going back -- co functions themselves return a Promise, so you will need to deal with that appropriately. But in general, we've found this to be a pretty robust solution, and I'm happy to help you figure it out in more detail.
You can have blocks that execute asynchronously without Promises, async functions, or callbacks by using the JS Interpreter (docs, GitHub), conveniently written by the same guy that created Blockly. JS Interpreter is a JavaScript-in-JavaScript implementation. This does mean there needs to be a lot of code to connect the functions/commands of the main JS VM to the interpreter's embedded implementation. Blockly has a few demonstrations of doing this (src). In particular, you'll want to investigate async-execution.html and the wait block implementation. You can find the wait block running live here. Conveniently, the interpreter's doc's section on External API happens to use XMLHttpRequest as its example implementation. This should should be a good starting point for your request block's implementation.
Creating a SOAP XMLHttpRequest request in JavaScript
I'm trying to create a SOAP request in JavaScript, but I get a wrong response. Here's my request: callSOAP() { var xmlhttp = new XMLHttpRequest(); xmlhttp.open('POST', 'https://webapi.allegro.pl/service.php', true); var sr = '<?xml version="1.0" encoding="utf-8"?>' + '<SOAP-ENV:Envelope ' + 'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' + 'xmlns:main="https://webapi.allegro.pl/service.php" ' + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + 'xmlns:xsd="http://www.w3.org/2001/XMLSchema">' + '<SOAP-ENV:Body>' + '<main:DoGetCountriesRequest>' + '<main:countryCode>1</main:countryCode>' + '<main:webapiKey>xxxxxxxx</main:webapiKey>' + '</main:DoGetCountriesRequest>' + '</SOAP-ENV:Body>' + '</SOAP-ENV:Envelope>'; xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { console.log(xmlhttp.response); } }; xmlhttp.setRequestHeader('Content-Type', 'text/xml'); xmlhttp.send(sr); } I try to call 'DoGetCountriesRequest' method but the response is status code 500 with a message 'Invalid XML'. Is it the proper way to call a SOAP method in JavaScript? What's wrong with my request?
It looks like you're sending the request to the ?wsdl endpoint - remove that from the URL in your xmlhttp.open() method call to send it to the service itself. It also seems your SOAP message is malformed - you've closed the SOAP-ENV:Envelope opening tag too early - it also needs to surround your xmlns:xsi and xmlns:xsd namespace definitions: '<?xml version="1.0" encoding="utf-8"?>' + '<SOAP-ENV:Envelope ' + 'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:main="https://webapi.allegro.pl/service.php"' + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + 'xmlns:xsd="http://www.w3.org/2001/XMLSchema">' + ... Follow up edit: There are some double quotes in your in your countryCode and webapiKey opening tags that need removing and it looks like the message itself doesn't comply with the WSDL - the operation doGetCountries in the WSDL needs a DoGetCountriesRequest object. Try something like: var sr = '<?xml version="1.0" encoding="utf-8"?>' + '<SOAP-ENV:Envelope ' + 'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' + 'xmlns:main="https://webapi.allegro.pl/service.php" ' + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + 'xmlns:xsd="http://www.w3.org/2001/XMLSchema">' + '<SOAP-ENV:Body>' + '<main:DoGetCountriesRequest>' + '<main:countryCode>1</main:countryCode>' + '<main:webapiKey>xxxxxxxx</main:webapiKey>' + '</main:DoGetCountriesRequest>' + '</SOAP-ENV:Body>' + '</SOAP-ENV:Envelope>';
AWS Signing and Javascript
I need to send HTTP request to AWS with signed request via Javascript. Sadly I cannot use the AWS SDK JS as its either for Node.js or browser, but I need to run it from Rhino JS environment. seems I am doing something very wrong as I get whatever I do same result - AWS was not able to validate the provided access credentials. :( The code I am using is same as the one Amazons is using as example (but in Python). I am using only one external lib so I can use HMCA &SHA. Any help is much appreciated (and needed as I am struggling for days by now...), so yeah - help! Thanks is advance! Cheers, Joro gs.include('jshashes'); var method = 'GET'; var service = 'ec2'; var host = 'ec2.amazonaws.com'; var region = 'us-east-1'; var endpoint = 'https://ec2.amazonaws.com'; var access_key = 'ACCESSKEY'; var secret_key = 'SECRET/KEY'; var request_parameters = 'AWSAccessKeyId' + access_key + 'Action=RunInstances&&ImageId=ami-b770fbd8'; function getSignatureKey(key, date, region, service){ var newKey = "AWS4" + key; var kDate = new Hashes.SHA256().b64_hmac(newKey, date); var kRegion = new Hashes.SHA256().b64_hmac(kDate, region); var kService = new Hashes.SHA256().b64_hmac(kRegion, service); var kSigning = new Hashes.SHA256().b64_hmac(kService, "aws4_request"); return kSigning; } var gdt = new GlideDateTime(); var datestamp = gdt.getDate().getByFormat('yyyyMMdd') + 'T' + gdt.getTime().getByFormat('HHmmss') + 'Z'; var amzdate = gdt.getDate().getByFormat('yyyyMMdd')+""; var canonical_uri = '/'; var canonical_querystring = request_parameters; var canonical_headers = 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n' var signed_headers = 'host;x-amz-date'; var payload_hash = new Hashes.SHA256().hex(""); var canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash; var algorithm = 'AWS4-HMAC-SHA256'; var credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'; var string_to_sign = algorithm + '\n' + amzdate + '\n' + credential_scope + '\n' + new Hashes.SHA256().hex(canonical_request); var signing_key = getSignatureKey(secret_key, datestamp, region, service); //Python //var signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest() var signature = new Hashes.SHA256().hex_hmac(signing_key, string_to_sign); var authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature var headers = {'x-amz-date':amzdate, 'Authorization':authorization_header} var request_url = endpoint + '?' + canonical_querystring var httpRequest = new GlideHTTPRequest(request_url); httpRequest.setRequestHeader(headers); var res = httpRequest.get(); gs.print(res.statusCode); gs.print(res.allHeaders); gs.print(res.body);
Check the URL construction. For one, the request_parameters have some missing and misplaced delimiters. var request_parameters = 'AWSAccessKeyId=' + access_key + '&Action=RunInstances&ImageId=ami-b770fbd8'; In addition to inspecting and testing the resulting URL, you might also try to simply the syntax to make it easier to check and update. Just as an example, the following var credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'; var string_to_sign = algorithm + '\n' + amzdate + '\n' + credential_scope + '\n' + new Hashes.SHA256().hex(canonical_request); could be written as follows (which seems easier to check to me): var credential_scope = [ datestamp, region, service, 'aws4_request' ].join('/'); var string_to_sign = [ algorithm, amzdate, credential_scope, new Hashes.SHA256().hex(canonical_request) ].join('\n');
Turning dynamic div content into a link
I am working on Longtail's JW Player and I am stuck with some basic stuff. I don't know what it is called in the programming language thats why I will write it step by step: There is a javascript code to show title and description of the playing video, as shown below <script type="text/javascript"> var player = null; var playlist = null; function playerReady(obj) { player = gid(obj.id); displayFirstItem(); }; function displayFirstItem() { try { playlist = player.getPlaylist(); } catch(e) { setTimeout("displayFirstItem()", 100); } player.addControllerListener('ITEM', 'itemMonitor'); itemMonitor({index:player.getConfig()['item']}); }; function itemMonitor(obj) { gid('nowplaying').innerHTML = 'Playing: ' + playlist[obj.index]['title'] + ''; gid('author').innerHTML = '<p>Author: ' + playlist[obj.index]['author'] + '</p>'; gid('description').innerHTML = '<p>Description: ' + playlist[obj.index]['description'] + '</p>'; }; function gid(name) { return document.getElementById(name); }; </script> Code returns the video title in to a div: <div id="nowplaying"></div> What I want is to display video title also in the tweet this button: href="http://twitter.com/home?status=SONG TITLE" How can I do this? Best regards
Edit the itemMonitor() function: function itemMonitor(obj) { gid('nowplaying').innerHTML = 'Playing: ' + playlist[obj.index]['title'] + ''; gid('author').innerHTML = '<p>Author: ' + playlist[obj.index]['author'] + '</p>'; gid('description').innerHTML = '<p>Description: ' + playlist[obj.index]['description'] + '</p>'; gid('tweetLink').href = 'http://twitter.com/home?status=' + encodeURIComponent(playlist[obj.index]['title']); }; This requires that a link be present in the document with id="tweetLink", this doesn't alter the link's text, however, if you want to update the link's text: function itemMonitor(obj) { gid('nowplaying').innerHTML = 'Playing: ' + playlist[obj.index]['title'] + ''; gid('author').innerHTML = '<p>Author: ' + playlist[obj.index]['author'] + '</p>'; gid('description').innerHTML = '<p>Description: ' + playlist[obj.index]['description'] + '</p>'; gid('tweetLink').href = 'http://twitter.com/home?status=' + encodeURIComponent(playlist[obj.index]['title']); gid('tweetLink').innerHTML = 'Tweet this song: ' + playlist[obj.index]['title'] + '.'; };