I'm having trouble with reading the content of a "TaskAttachment" that I uploaded from one extension to another.
I'm using this code to get the "TaskAttachment", I'm getting it with the right name and URL, (Which I get have access to without nay authentication, e.g. from another clean browser)
var taskClient = DT_Client.getClient();
taskClient.getPlanAttachments(vsoContext.project.id, "build", build.orchestrationPlan.planId, "MyExtType").then((taskAttachments) => {
$.each(taskAttachments, (index, taskAttachment) => {
if (taskAttachment._links && taskAttachment._links.self && taskAttachment._links.self.href) {
var link = taskAttachment._links.self.href;
var attachmentName = taskAttachment.name;
var fileContent = readText(link);
...
And this javascript function to read the content
...
var readText = function readTextFile(file)
{
alert("file = " + file);
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function ()
{
alert("rawFile.readyState = " + rawFile.readyState);
alert("rawFile.status = " + rawFile.status);
alert("rawFile.responseText = " + rawFile.responseText);
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
alert(allText);
return allText;
}
}
}
rawFile.send(null);
return "Failed to get data..";
}
The problem is that I'm getting 401 error message :
"IIS 7.5 Detailed Error - 401.2 - Unauthorized"
How can I read this file content? Is there a better way to transfer data from a "Build Step Extension" to a "UI Extension" that present the data in the build summary page (new tab)?
According to "IIS 7.5 Detailed Error - 401.2 - Unauthorized" It's most likely due to directory permissions set in the file system.
Make sure Anonymous access is enabled on IIS -> Authentication.
Right click on it, then click on Edit, and choose a domain\username and password.
I just managed to read the attachment data using the "getAttachmentContent" method:
I'm not sure why MS doesn't put any reference to this function in the tutorial, after long digging in the documentation \ Q&A I found it.
taskClient.getPlanAttachments(vsoContext.project.id, "build", build.orchestrationPlan.planId, "My_Attachment_Type").then((taskAttachments) => {
$.each(taskAttachments, (index, taskAttachment) => {
if (taskAttachment._links && taskAttachment._links.self && taskAttachment._links.self.href) {
var recId = taskAttachment.recordId;
var timelineId = taskAttachment.timelineId;
taskClient.getAttachmentContent(vsoContext.project.id, "build", build.orchestrationPlan.planId,timelineId,recId,"My_Attachment_Type",taskAttachment.name).then((attachementContent)=> {
function arrayBufferToString(buffer){
var arr = new Uint8Array(buffer);
var str = String.fromCharCode.apply(String, arr);
return str;
}
var data = arrayBufferToString(attachementContent);
Related
I am building an Office Excel Add-in using the web add-in framework provided by Microsoft.
This add-in also includes a custom function. Currently, the custom function is working on Excel for Mac, Excel online (device agnostic), but not on Windows?
The add-in loads fine, and there are no obvious errors. But when the function is run (on Windows) it just says:
#BUSY and then resolves to #VALUE! and stays like that.
The code also works when using the Shared Runtime configuration, but that requires that we make all our Javascript compatible with IE, which is definitely a possibility - but I would like to know why the regular configuration is not working.
WISE is the Excel function.
function WISE(symbol, parameter, year, quarter) {
var param = parameter.replace(/\s/g, '').toLowerCase();
param = param.replace('&', 'and');
symbol = symbol.toUpperCase();
if (quarter == null) {
return getAnnualData(symbol, param, year);
}
}
function getVal(data, param) {
var apiResponseDataFormatted = {};
for (var key in data) {
apiResponseDataFormatted[key.replace(/ /g, '').toLowerCase()] = data[key];
}
var newValue = apiResponseDataFormatted[param];
if (newValue !== 0 && !newValue) {
newValue = 'Unavailable';
}
return newValue;
}
function getAnnualData(symbol, parameter, year) {
var apiPath = requestMap[parameter];
var response = "";
var url = URL_API + "/" + apiPath + "/" + symbol + "?apikey=" + api_key;
var request = new XMLHttpRequest();
request.open('GET', url, false); // `false` makes the request synchronous
request.send(null);
if (request.status === 200) {// That's HTTP for 'ok'
response = JSON.parse(request.responseText);
}else{
return "Request Error: " + request.status + " " + url;
}
var apiResponseData;
var currentYear = new Date().getFullYear();
if (year != null && year !== currentYear) {
apiResponseData = response[currentYear - year - 1];
} else {
apiResponseData = response[0];
}
result = getVal(apiResponseData, parameter)
return result;
}
sorry for the frustration. One of the main reason for this could be that currently on windows custom functions run in their own runtime, which is a seperate. While that runtime conserves memory, one of the limitations is it doesn't support Full CORS.
We have been recommending the use of the Shared Runtime as a way to get around this. This effectively will run the custom function in the same runtime as the taskpane, so I suspect will work for you. This also makes it easy to share state between taskpanes and functions.
Can you try that?
https://learn.microsoft.com/en-us/office/dev/add-ins/tutorials/share-data-and-events-between-custom-functions-and-the-task-pane-tutorial
(I realize the docs aren't super clear about this, so will follow up offline on this to get it corrected).
I wasn't in charge of the Apache configuration, so I'm not sure what I can provide in terms of useful conf text, but I'm fairly certain I have narrowed the problem down to the login. EventSource works flawlessly both locally on XAMPP without any login and once you refresh the page after authenticating on the production server, but that first load on the server just will not open a connection. Has anyone seen this problem before? I couldn't find anything on the internet about this after searching for the past few days.
Edit: Some code
Some of the server-side code (which mostly shouldn't be relevant):
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$client_stream = new RedisStream();
$client_stream->poll(1); //The loop, with sleep time as a parameter
The JavaScript:
var xhttpViewSet;
var xhttpSearch;
var view = 'tile';
var search = '';
var seed_url = '/core/seed_view.php';
var stream_url = '/core/stream.php';
var default_class = 'panel-default';
var success_class = 'panel-success';
var warning_class = 'panel-warning';
var danger_class = 'panel-danger';
function UpdateClient(c_name, c_obj) {
if ((c_element = document.getElementById(c_name)) !== null) {
c_element.classList.remove('text-muted');
c_element.classList.remove(default_class);
c_element.classList.remove(success_class);
c_element.classList.remove(warning_class);
c_element.classList.remove(danger_class);
switch (c_obj['status']) {
case 0:
c_obj['status'] = 'OK';
c_element.classList.add(success_class)
break;
case 1:
c_obj['status'] = 'Warning';
c_element.classList.add(warning_class)
break;
case 2:
c_obj['status'] = 'Critical';
c_element.classList.add(danger_class)
break;
default:
c_obj['status'] = 'Unknown';
c_element.classList.add(danger_class)
break;
}
for (i in c_obj) {
var var_nodes = c_element.getElementsByClassName(i);
if (var_nodes.length > 0) {
for (var j = var_nodes.length - 1; j >= 0; j--) {
var_nodes[j].innerHTML = c_obj[i];
}
}
}
}
}
function SetView() {
var view_url = seed_url + '?search=' + search + '&view=' + view;
xhttpViewSet.open('GET', view_url, true);
xhttpViewSet.send();
}
var main = function() {
container = document.getElementById('content');
if (new XMLHttpRequest()) {
xhttpViewSet = new XMLHttpRequest();
xhttpSearch = new XMLHttpRequest();
} else {
xhttpViewSet = new ActiveXObject('Microsoft.XMLHTTP');
xhttpSearch = new ActiveXObject('Microsoft.XMLHTTP');
}
var stream = new EventSource(stream_url);
stream.onopen = function() {
console.log('Connection opened.'); //This doesn't fire
}
stream.onmessage = function(e) {
var c_obj = JSON.parse(e.data);
UpdateClient(c_obj.name, c_obj.value);
};
xhttpViewSet.onreadystatechange = function() {
if (xhttpViewSet.readyState == 4) {
var resp = xhttpViewSet.responseText;
if (xhttpViewSet.status == 200 && resp.length > 0) {
container.innerHTML = resp;
if (view == 'list') {
$('#computer-table').DataTable({
"lengthMenu": [[25, 50, 100], [25, 50, 100]]
});
}
} else {
container.innerHTML = '<error>No computers matched your search or an error occured.</error>';
}
}
}
SetView(); //This successfully does all but make the EventSource connection, and only fails to do that on first load
document.getElementById('list-view').addEventListener('click', function() {
view = 'list';
SetView();
});
document.getElementById('tile-view').addEventListener('click', function() {
view = 'tile';
SetView();
});
document.getElementById('search').addEventListener('keyup', function() {
search = this.value.toUpperCase();
SetView();
});
document.getElementById('clear-search').addEventListener('click', function() {
document.getElementById('search').value = '';
search = '';
SetView();
});
};
window.onload = main;
It is a bit hard to know for sure without a lot more information, but based on what you have said so far, I think it is one of:
HEAD/OPTIONS: Some browsers will send a HEAD or OPTIONS http call to a server script, before they send the GET or POST. The purpose of sending OPTIONS is to ask what headers are allowed to be sent. It is possible this is happening as part of the login process; that might explain why it works when you reload. See chapter 9 of Data Push Apps with HTML5 SSE (disclaimer: my book) for more details; basically, at the top of your SSE script you need to check the value of $_SERVER["REQUEST_METHOD"] and if it is "OPTIONS", intercept and say what headers you want to accept. I've used this one before:
header("Access-Control-Allow-Headers: Last-Event-ID,".
" Origin, X-Requested-With, Content-Type, Accept,".
" Authorization");`
CORS: The HTML page URL and the SSE page URL must have identical origins. There are detailed explanations (specific to SSE) in chapter 9 of Data Push Apps with HTML5 SSE (again), or (less specifically) at Wikipedia. If this is the problem, look into adding header("Access-Control-Allow-Origin: *"); to your SSE script.
withCredentials: There is a second parameter to the SSE constructor, and you use it like this: var stream = new EventSource(stream_url, { withCredentials: true }); It is saying it is okay to send the auth credentials. (Again, chapter 9 of the book goes into more detail - sorry for the repeated plugs!) There is a second step, over on the server-side: at the top of your PHP SSE script you need to add the following.
header("Access-Control-Allow-Origin: ".#$_SERVER["HTTP_ORIGIN"]);
header("Access-Control-Allow-Credentials: true");
PHP Sessions locking: This normally causes the opposite problem, which is that the SSE script has locked the PHP session, so no other PHP scripts work. See https://stackoverflow.com/a/30878764/841830 for how to handle it. (It is a good idea to do this anyway, even if it isn't your problem.)
I am unable to print response for below :
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<head>
<script>
jQuery.noConflict();
jQuery(document).ready(function() {
alert("Hello world, part 2!");
callOtherDomain();
});
function callOtherDomain() {
var invocation = new XMLHttpRequest();
var uName = "";
var pWord = "";
var project = '';
var domain = '';
var url = 'https://url';
invocation.open('GET', url, true, uName, pWord, project, domain);
invocation.onreadystatechange = function () {
if (4 != invocation.readyState) {
return;
}
if (200 != invocation.status) {
return;
}
console.log(this.responseText);
console.log(invocation.responseText);
console.log(invocation);
};
invocation.send();
}
I get value for console.log(invocation); as - [object XMLHttpRequest] and this.responseText prints - undefined.
When using the same credentials with chrome extension for REST API I can see the response.
I have tried printing - var xmlResponse = invocation.responseXML; - gives 'null'
var xmlResponse1 = invocation.responseText; also prints whitespace/blank
console.log(invocation.status); - print 200 (which means the call is made successfully)
I am also getting console.log(invocation.readyState); - as 4.
Here is the details shown on that network tab snag.gy/kdcwc.jpg, does is mean the response is received
var headers = invocation.getAllResponseHeaders();
alert(headers);
All the headers are also printing blank/whitespace.
anyone can help please ?
I am trying to implement a solution where by using PhantomJS a web location is open evaluated and the output is saved to a file for processing. Specifically the scanning for malicious scripts. I have been able to implement the solution using PhantomJS running once. For example this works perfectly...
var system = require('system');
var page = require('webpage').create();
var lastReceived = new Date().getTime();
var requestCount = 0;
var responseCount = 0;
var requestIds = [];
var fileSystem = require('fs');
var startTime = new Date().getTime();
page.onResourceReceived = function (response) {
if(requestIds.indexOf(response.id) !== -1) {
lastReceived = new Date().getTime();
responseCount++;
requestIds[requestIds.indexOf(response.id)] = null;
}
};
page.onResourceRequested = function (request) {
if(requestIds.indexOf(request.id) === -1) {
requestIds.push(request.id);
requestCount++;
}
};
page.open('http://adserver.example.com/adserve/;ID=164857;size=300x250;setID=162909;type=iframe', function () {});
var checkComplete = function () {
// We don't allow it to take longer than 5 seconds but
// don't return until all requests are finished
if((new Date().getTime() - lastReceived > 300 && requestCount === responseCount) || new Date().getTime() - startTime > 5000) {
clearInterval(checkCompleteInterval);
console.log(page.content);
phantom.exit();
}
}
var checkCompleteInterval = setInterval(checkComplete, 1);
However, I have had immense difficulty trying to create and automated system that doesn't require PhantomJS to continually be restarted which has a fair bit of overhead.
I tried using a named pipe to read from and then attempt to open the passed url, but for some reason it will not open properly. I would love and deeply appreciate any guidance on this.
One thing to mention is that PhantomJS excels in HTTP communications. That's why for advanced features & better performance, I always use resource pooling pattern + webserver module. This module is still tagged EXPERIMENTAL, but I have always found it quite stable until now.
So, I think the best in your case it's better to communicate via HTTP than via files IO.
Here is a very basic example :
var page = require('webpage').create();
var server = require('webserver').create();
var system = require('system');
var host, port;
if (system.args.length !== 2) {
console.log('Usage: server.js <some port>');
phantom.exit(1);
} else {
port = system.args[1];
var listening = server.listen(port, function (request, response) {
var page=require('webpage').create();
page.open(request.post.target, function(status){
response.write("Hello "+page.title);
response.close();
});
});
if (!listening) {
console.log("could not create web server listening on port " + port);
phantom.exit();
}
//test only
var url = "http://localhost:" + port + "/";
console.log("SENDING REQUEST TO:");
console.log(url);
var data='target=http://stackoverflow.com/';
page.open(url,'post', data, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
} else {
console.log("GOT REPLY FROM SERVER:");
console.log(page.content);
}
phantom.exit();
});
}
var soapre1 = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:glob=\"http://sap.com/xi/SAPGlobal20/Global\">";
var soapre2 = "<soapenv:Header/><soapenv:Body><glob:EmployeeLeaveRequestByParticipantQuery><EmployeeLeaveRequestSelectionByParticipant><EmployeeLeaveRequestParticipantRoleCode listVersionID=\"?\">2</EmployeeLeaveRequestParticipantRoleCode>";
var soapre3 = "<!--Zero or more repetitions:--> <EmployeeLeaveRequestParticipantWorkAgreementIDInterval><IntervalBoundaryTypeCode>1</IntervalBoundaryTypeCode> <!--Optional:--> <LowerBoundaryWorkAgreementID schemeID=\"?\" schemeAgencyID=\"?\">1009</LowerBoundaryWorkAgreementID></EmployeeLeaveRequestParticipantWorkAgreementIDInterval>";
var soapre4 = " <!--Zero or more repetitions:--> </EmployeeLeaveRequestSelectionByParticipant></glob:EmployeeLeaveRequestByParticipantQuery> </soapenv:Body></soapenv:Envelope>";
var soapRequest = soapre1+soapre2+soapre3+soapre4;
var authstr = 'Basic ' +Titanium.Utils.base64encode('S0009231839'+':'+ 'm8390967743!');
var soapxhr = Ti.Network.createHTTPClient();
soapxhr.setRequestHeader('SOAPAction',soapRequest);
soapxhr.open("POST","http://erp.esworkplace.sap.com/sap/bc/srt/pm/sap/ecc_empleavereqparctqr/800/default_profile/2/binding_t_http_a_http_ecc_empleavereqparctqr_default_profile");
soapxhr.setRequestHeader('Authorization', authstr);
soapxhr.setRequestHeader('Content-Type','text/xml','charset=utf-8');
soapxhr.send();
soapxhr.onload = function(e)
{
Ti.API.info('abcd');
//get the xml data and let it roll!
var doc = this.responseXML;
Ti.API.info(doc);
}
soapxhr.onerror = function (e){
alert('Error');
Ti.API.info(e);
}
Unable to load the response Its directly getting error
[INFO] {
source = "[object TiNetworkClient]";
type = error;
}
Any one advice how to fix the issue!
# Thanks in advance
In all browser its saying error! but i found some wsdl and soap request so in order to open the response i need to pass the method name to the http request ! then it working