From 2a42a3618bd786e3b8b6eb5048b03932bc6eeedb Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Mon, 17 Sep 2012 22:34:21 +1200 Subject: [PATCH 01/14] Add CORS example. --- CORS/SimpleDashboard/app.js | 148 ++++++++++++++++++++++++++++++ CORS/SimpleDashboard/example.html | 13 +++ CORS/SimpleDashboard/styles.css | 126 +++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 CORS/SimpleDashboard/app.js create mode 100644 CORS/SimpleDashboard/example.html create mode 100644 CORS/SimpleDashboard/styles.css diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js new file mode 100644 index 0000000..cca9d45 --- /dev/null +++ b/CORS/SimpleDashboard/app.js @@ -0,0 +1,148 @@ +$(document).ready(function(){ + $.ajaxSetup({ accepts: "application/json" }); +}); + +etUrl = "https://ettrial.catchsoftware.net"; +apiUrl = etUrl + "/api"; +searchUrl = apiUrl + "/search"; +login = "viewonly"; +pass = "view2012"; + +function readableEntityName(type) { + switch (type) + { + case "testscript": + return "Scripts"; + case "testscriptassignment": + return "Assignments"; + case "requirement": + return "User Stories"; + case "agilerun": + return "Adhoc Runs"; + case "automatedtest": + return "Automated Tests"; + case "automatedtestassignment": + return "Automated Runs"; + case "incident": + return "Issues"; + default: + return type; + } +} + +function tqlAggregateSearch(tql, success){ + $.ajax({ + url: searchUrl, + type: "GET", + username: login, + password: pass, + data: "tql=" + escape(tql), + xhrFields: { + withCredentials: true + }, + crossDomain: true, + success: success + }); +} + +function tqlSearch(tql, top, format, success){ + $.ajax({ + url: searchUrl, + type: "GET", + username: login, + password: pass, + data: "tql=" + escape(tql) + "&$top=" + top + "&format=" + format, + xhrFields: { + withCredentials: true + }, + crossDomain: true, + success: success + }); +} + +function formatDate(date){ + var d = date.getDate(); + var m = date.getMonth()+1; + var y = date.getFullYear(); + return '' + y +'-'+ (m<=9?'0'+m:m) +'-'+ (d<=9?'0'+d:d); +} + +function drawSearchResults(tql, projectName, elementId) { + var max = 5; + tqlSearch(tql, max, "grid", function(data) { + var content = ''; + + if (data.Items.length > 0) { + content += ''; + } else { + content += '...No data...'; + } + + $(elementId).append(content); + }); +} + +function drawRecentlyUpdated(elementId, projectName) { + var tql = "Project = \"" + projectName + "\" ORDER BY LastUpdatedAt DESC"; + var elId = '#' + elementId + ' .recently-updated'; + drawSearchResults(tql, projectName, elId); +} + +function drawRecentlyFailed(elementId, projectName) { + var tql = "Status = Failed AND Project = \"" + projectName + "\" ORDER BY LastUpdatedAt DESC"; + var elId = '#' + elementId + ' .recently-failed'; + drawSearchResults(tql, projectName, elId); +} + +function drawChart(projectName, group) { + var data = []; + + for (entityType in group) { + var count = group[entityType].COUNT; + data.push([readableEntityName(entityType), count]); + } + + if (data.length == 0) return; + + var dataTable = google.visualization.arrayToDataTable(data); + + var options = { + title: projectName + ' Stats' + }; + + var elementId = projectName.replace(' ','_').replace("'",""); + + var content = '
' + + '
Recently Updated
' + + '
Recently Failed
'; + + $('.results').append(content); + + $('#' + elementId + ' .totals-chart').each(function() { + var chart = new google.visualization.PieChart(this); + chart.draw(dataTable, options); + drawRecentlyUpdated(elementId, projectName); + drawRecentlyFailed(elementId, projectName); + }); +} + +function drawCharts() { + tqlAggregateSearch('GROUP BY Project { GROUP BY EntityType { COUNT } }', function(data) { + for (projectName in data.Results.GroupByProject) { + var group = data.Results.GroupByProject[projectName].GroupByEntityType; + drawChart(projectName, group); + } + }); +} + +google.load("visualization", "1", {packages:["corechart"]}); + +google.setOnLoadCallback(drawCharts); diff --git a/CORS/SimpleDashboard/example.html b/CORS/SimpleDashboard/example.html new file mode 100644 index 0000000..d27ccfc --- /dev/null +++ b/CORS/SimpleDashboard/example.html @@ -0,0 +1,13 @@ + + + + + + + +

CORS Dashboard Example

+

This page demonstrates using CORS to retrieve a list of projects with entity counts, and then a list of recently updated and recently failed entities associated with each project from the Enterprise Tester REST API.

+
+ - +

CORS Dashboard Example

This page demonstrates using CORS to retrieve a list of projects with entity counts, and then a list of recently updated and recently failed entities associated with each project from the Enterprise Tester REST API.

- \ No newline at end of file From 45ff7f08867e6b66d8b3d49ddf6587d619187eef Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Mon, 17 Sep 2012 22:45:38 +1200 Subject: [PATCH 03/14] Added note RE: availability of CORS and JSONP support in API. --- CORS/SimpleDashboard/example.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CORS/SimpleDashboard/example.html b/CORS/SimpleDashboard/example.html index f297f84..2569b86 100644 --- a/CORS/SimpleDashboard/example.html +++ b/CORS/SimpleDashboard/example.html @@ -7,6 +7,9 @@

CORS Dashboard Example

This page demonstrates using CORS to retrieve a list of projects with entity counts, and then a list of recently updated and recently failed entities associated with each project from the Enterprise Tester REST API.

+

+ Note: CORS and JSONP support is only available in Enterprise Tester version 4.4 and above. +

From 9af6df560e3b264843bd4eab415ad6ea24c350dd Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 00:14:48 +1200 Subject: [PATCH 04/14] Added warning about only google chrome being supported. --- CORS/SimpleDashboard/example.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/example.html b/CORS/SimpleDashboard/example.html index 2569b86..e9be798 100644 --- a/CORS/SimpleDashboard/example.html +++ b/CORS/SimpleDashboard/example.html @@ -8,7 +8,7 @@

CORS Dashboard Example

This page demonstrates using CORS to retrieve a list of projects with entity counts, and then a list of recently updated and recently failed entities associated with each project from the Enterprise Tester REST API.

- Note: CORS and JSONP support is only available in Enterprise Tester version 4.4 and above. + Note: CORS and JSONP support is only available in Enterprise Tester version 4.4 and above, and this demo currently is only tested/supported in Google Chrome (but unfortunately not Chrome for iOS).

From 3c8e69b035b72874b0d25745986b5c2575360da3 Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 00:25:00 +1200 Subject: [PATCH 05/14] Switched from HTTPS to HTTP for example ettrial URL. --- CORS/SimpleDashboard/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index cca9d45..0af6888 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -2,7 +2,7 @@ $(document).ready(function(){ $.ajaxSetup({ accepts: "application/json" }); }); -etUrl = "https://ettrial.catchsoftware.net"; +etUrl = "http://ettrial.catchsoftware.net"; apiUrl = etUrl + "/api"; searchUrl = apiUrl + "/search"; login = "viewonly"; From 23d317586638be601735375ef0468a9a2a08f899 Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 07:55:39 +1200 Subject: [PATCH 06/14] Switched to set authorization header. --- CORS/SimpleDashboard/app.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index 0af6888..48a5027 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -33,14 +33,15 @@ function readableEntityName(type) { function tqlAggregateSearch(tql, success){ $.ajax({ url: searchUrl, - type: "GET", - username: login, - password: pass, - data: "tql=" + escape(tql), + type: "GET", + data: "tql=" + escape(tql), xhrFields: { withCredentials: true }, crossDomain: true, + beforeSend: function(xhr) { + xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password) + }, success: success }); } @@ -49,13 +50,14 @@ function tqlSearch(tql, top, format, success){ $.ajax({ url: searchUrl, type: "GET", - username: login, - password: pass, - data: "tql=" + escape(tql) + "&$top=" + top + "&format=" + format, + data: "tql=" + escape(tql) + "&$top=" + top + "&format=" + format, xhrFields: { withCredentials: true }, crossDomain: true, + beforeSend: function(xhr) { + xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password) + }, success: success }); } From 987201f00091fab5dec45ca2f786dd21b51c3920 Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 07:57:05 +1200 Subject: [PATCH 07/14] Switched to set authorization header (missing closing parens last time). --- CORS/SimpleDashboard/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index 48a5027..c614437 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -40,7 +40,7 @@ function tqlAggregateSearch(tql, success){ }, crossDomain: true, beforeSend: function(xhr) { - xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password) + xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password)); }, success: success }); @@ -56,7 +56,7 @@ function tqlSearch(tql, top, format, success){ }, crossDomain: true, beforeSend: function(xhr) { - xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password) + xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password)); }, success: success }); From e89fb8791e7c099bf972ac6439732a88a6d310c3 Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 07:58:06 +1200 Subject: [PATCH 08/14] Fixed incorrect password variable. --- CORS/SimpleDashboard/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index c614437..d618188 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -6,7 +6,7 @@ etUrl = "http://ettrial.catchsoftware.net"; apiUrl = etUrl + "/api"; searchUrl = apiUrl + "/search"; login = "viewonly"; -pass = "view2012"; +password = "view2012"; function readableEntityName(type) { switch (type) From 2ecf44eb572096be340547d63dacfd44fce2c065 Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 08:06:59 +1200 Subject: [PATCH 09/14] Added base64 encoded authorization header. --- CORS/SimpleDashboard/app.js | 12 +-- CORS/SimpleDashboard/base64.js | 170 ++++++++++++++++++++++++++++++ CORS/SimpleDashboard/example.html | 1 + 3 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 CORS/SimpleDashboard/base64.js diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index d618188..2757ce1 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -30,6 +30,10 @@ function readableEntityName(type) { } } +function addBasicAuthHeader(xhr) { + xhr.setRequestHeader("Authorization", "Basic " + Base64.encode(login + ":" + password)); +} + function tqlAggregateSearch(tql, success){ $.ajax({ url: searchUrl, @@ -39,9 +43,7 @@ function tqlAggregateSearch(tql, success){ withCredentials: true }, crossDomain: true, - beforeSend: function(xhr) { - xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password)); - }, + beforeSend: addBasicAuthHeader success: success }); } @@ -55,9 +57,7 @@ function tqlSearch(tql, top, format, success){ withCredentials: true }, crossDomain: true, - beforeSend: function(xhr) { - xhr.setRequestHeader("Authorization", "Basic " + encodeBase64(login + ":" + password)); - }, + beforeSend: addBasicAuthHeader success: success }); } diff --git a/CORS/SimpleDashboard/base64.js b/CORS/SimpleDashboard/base64.js new file mode 100644 index 0000000..2e8d1a5 --- /dev/null +++ b/CORS/SimpleDashboard/base64.js @@ -0,0 +1,170 @@ +var Base64 = (function() { + "use strict"; + + var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var _utf8_encode = function (string) { + + var utftext = "", c, n; + + string = string.replace(/\r\n/g,"\n"); + + for (n = 0; n < string.length; n++) { + + c = string.charCodeAt(n); + + if (c < 128) { + + utftext += String.fromCharCode(c); + + } else if((c > 127) && (c < 2048)) { + + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + + } else { + + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + + } + + } + + return utftext; + }; + + var _utf8_decode = function (utftext) { + var string = "", i = 0, c = 0, c1 = 0, c2 = 0; + + while ( i < utftext.length ) { + + c = utftext.charCodeAt(i); + + if (c < 128) { + + string += String.fromCharCode(c); + i++; + + } else if((c > 191) && (c < 224)) { + + c1 = utftext.charCodeAt(i+1); + string += String.fromCharCode(((c & 31) << 6) | (c1 & 63)); + i += 2; + + } else { + + c1 = utftext.charCodeAt(i+1); + c2 = utftext.charCodeAt(i+2); + string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63)); + i += 3; + + } + + } + + return string; + }; + + var _hexEncode = function(input) { + var output = '', i; + + for(i = 0; i < input.length; i++) { + output += input.charCodeAt(i).toString(16); + } + + return output; + }; + + var _hexDecode = function(input) { + var output = '', i; + + if(input.length % 2 > 0) { + input = '0' + input; + } + + for(i = 0; i < input.length; i = i + 2) { + output += String.fromCharCode(parseInt(input.charAt(i) + input.charAt(i + 1), 16)); + } + + return output; + }; + + var encode = function (input) { + var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0; + + input = _utf8_encode(input); + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output += _keyStr.charAt(enc1); + output += _keyStr.charAt(enc2); + output += _keyStr.charAt(enc3); + output += _keyStr.charAt(enc4); + + } + + return output; + }; + + var decode = function (input) { + var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + + enc1 = _keyStr.indexOf(input.charAt(i++)); + enc2 = _keyStr.indexOf(input.charAt(i++)); + enc3 = _keyStr.indexOf(input.charAt(i++)); + enc4 = _keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output += String.fromCharCode(chr1); + + if (enc3 !== 64) { + output += String.fromCharCode(chr2); + } + if (enc4 !== 64) { + output += String.fromCharCode(chr3); + } + + } + + return _utf8_decode(output); + }; + + var decodeToHex = function(input) { + return _hexEncode(decode(input)); + }; + + var encodeFromHex = function(input) { + return encode(_hexDecode(input)); + }; + + return { + 'encode': encode, + 'decode': decode, + 'decodeToHex': decodeToHex, + 'encodeFromHex': encodeFromHex + }; +}()); \ No newline at end of file diff --git a/CORS/SimpleDashboard/example.html b/CORS/SimpleDashboard/example.html index e9be798..cb594c1 100644 --- a/CORS/SimpleDashboard/example.html +++ b/CORS/SimpleDashboard/example.html @@ -2,6 +2,7 @@ + From 2c7feb35ac5e28f72297ebf8f8e2bbdbcd3f979e Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 08:08:28 +1200 Subject: [PATCH 10/14] Fixed missing comma --- CORS/SimpleDashboard/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index 2757ce1..d5dfee0 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -43,7 +43,7 @@ function tqlAggregateSearch(tql, success){ withCredentials: true }, crossDomain: true, - beforeSend: addBasicAuthHeader + beforeSend: addBasicAuthHeader, success: success }); } @@ -57,7 +57,7 @@ function tqlSearch(tql, top, format, success){ withCredentials: true }, crossDomain: true, - beforeSend: addBasicAuthHeader + beforeSend: addBasicAuthHeader, success: success }); } From 6efdb29b5b57c70f8616c30d647a3fd8991beace Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 08:23:42 +1200 Subject: [PATCH 11/14] Set data type on XHR requests to JSON. --- CORS/SimpleDashboard/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index d5dfee0..3b1f4d5 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -38,7 +38,8 @@ function tqlAggregateSearch(tql, success){ $.ajax({ url: searchUrl, type: "GET", - data: "tql=" + escape(tql), + data: "tql=" + escape(tql), + dataType: "json", xhrFields: { withCredentials: true }, @@ -53,6 +54,7 @@ function tqlSearch(tql, top, format, success){ url: searchUrl, type: "GET", data: "tql=" + escape(tql) + "&$top=" + top + "&format=" + format, + dataType: "json", xhrFields: { withCredentials: true }, From 12690e7767adb9c9e559506ea322cfd82f52d405 Mon Sep 17 00:00:00 2001 From: Alex Henderson Date: Tue, 18 Sep 2012 08:31:47 +1200 Subject: [PATCH 12/14] Updated CORS example to include correct list of platforms where this example works/does not work. --- CORS/SimpleDashboard/example.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/example.html b/CORS/SimpleDashboard/example.html index cb594c1..6d95e06 100644 --- a/CORS/SimpleDashboard/example.html +++ b/CORS/SimpleDashboard/example.html @@ -9,7 +9,7 @@

CORS Dashboard Example

This page demonstrates using CORS to retrieve a list of projects with entity counts, and then a list of recently updated and recently failed entities associated with each project from the Enterprise Tester REST API.

- Note: CORS and JSONP support is only available in Enterprise Tester version 4.4 and above, and this demo currently is only tested/supported in Google Chrome (but unfortunately not Chrome for iOS). + Note: CORS and JSONP support is only available in Enterprise Tester version 4.4 and above, and is browser dependent. This example has been tested successfully on Safari, Safari on iOS, Chrome, Firefox and is known to not work on Internet Explorer, or Chrome for iOS currently.

From 58b0b6e1ff502a3f3579beced167eeef34464716 Mon Sep 17 00:00:00 2001 From: Igor Lyulev Date: Tue, 14 Jun 2016 13:35:35 +1200 Subject: [PATCH 13/14] update CORS example --- CORS/SimpleDashboard/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index 3b1f4d5..7f85dfe 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -2,7 +2,7 @@ $(document).ready(function(){ $.ajaxSetup({ accepts: "application/json" }); }); -etUrl = "http://ettrial.catchsoftware.net"; +etUrl = "http://etstaging01.catchsoftware.net/EnterpriseTesterMaster"; apiUrl = etUrl + "/api"; searchUrl = apiUrl + "/search"; login = "viewonly"; From 9ae0928cffb3f3d2bc05a1f0b3f4696a516afac9 Mon Sep 17 00:00:00 2001 From: Igor Lyulev Date: Tue, 14 Jun 2016 13:51:15 +1200 Subject: [PATCH 14/14] fixing cors --- CORS/SimpleDashboard/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CORS/SimpleDashboard/app.js b/CORS/SimpleDashboard/app.js index 7f85dfe..cc253c3 100644 --- a/CORS/SimpleDashboard/app.js +++ b/CORS/SimpleDashboard/app.js @@ -116,7 +116,7 @@ function drawChart(projectName, group) { if (data.length == 0) return; - var dataTable = google.visualization.arrayToDataTable(data); + var dataTable = google.visualization.arrayToDataTable(data, true); var options = { title: projectName + ' Stats'