Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ Takes a url, either relative to the *qcbin/rest/* url or relative to the *qcbin/
*[integer/string]* How many items to retrieve or 'max' to get as many as allowed by the ALM instance (can be configured in site administration interface).
###### page
*Not yet implemeted*
###### startIndex
*[integer/String]* Fetch rows starting from a row number or index*
###### fields
*[Array]* Which fields to retrieve, using this can greatly improve API speed. Skipping description fields etc lessens the size of the response body.
###### filter
Expand Down Expand Up @@ -178,4 +180,4 @@ npm test
However, if you want to run the integration or learning tests you'll need to provide connection information to your own ALM instance.
Do this by copying the [test/conn_info_example.json](https://github.com/ddikman/QC.js/blob/master/test/conn_info_example.json) and saving it in the same folder but named *conn_info.json*.

The tests will then pick up the connection info from there and the tests can be run, of course they might fail if your project looks different.
The tests will then pick up the connection info from there and the tests can be run, of course they might fail if your project looks different.
79 changes: 57 additions & 22 deletions qcApi.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
var Promise = require('promise');
var cookies = require('cookie');
var util = require('util');
var xml2js = require('xml2js');
require('String.prototype.repeat');
require('buffer-concat/polyfill');
var Client = new require('node-rest-client').Client;

InvalidAuthenticationException = function(msg){
Expand Down Expand Up @@ -50,7 +53,7 @@ qcApi.prototype.startSession = function(){

this.client.post(this.rootUrl + "/rest/site-session", { headers: { cookie : this.authCookie } }, function(data, res){

if(res.statusCode != 201)
if(res.statusCode != 201 && res.statusCode != 200)
{
reject("Session start failed, status code " + res.statusCode);
return;
Expand All @@ -76,10 +79,10 @@ qcApi.prototype.login = function(connInfo){
this.client = this.getClient({user: connInfo.user, password: connInfo.password});
this.domain = connInfo.domain;
this.project = connInfo.project;

this.client.get(this.rootUrl + "/authentication-point/authenticate", function handleAuthResponse(data, res){

if(res.statusCode == 200)
if(res.statusCode == 200 || res.statusCode == 201)
{
this.isAuthenticated = true;
this.authCookie = res.headers['set-cookie'].join(';');
Expand Down Expand Up @@ -112,37 +115,50 @@ qcApi.prototype.verifyAuthenticated = function(){
throw new InvalidAuthenticationException("Not yet logged in, please call login to authenticate.");
}

qcApi.prototype.convertEntity = function(entity){
var convertedEntity = {
type: entity['$'].Type
};

entity.Fields[0].Field.forEach(function(field){
var name = field['$'].Name;
name = name.replace(/(-\b[a-z](?!\s))/g, function(x){return x.toUpperCase();});
name = name.replace(/-/g, '');
var value = field.Value ? field.Value[0] : null;
convertedEntity[name] = value;
});

return convertedEntity;
};

/**
* If the REST call response is an entity, some processing is performed on the resulting javascript object, such as putting each field as a property
* on the object instead of an object in the entities property list
* @param {obj} Should be a javascript object returned from the node-rest-client, parsed from a REST call xml or json response
*/
qcApi.prototype.convertResult = function(obj){

if(obj.Entities == undefined)
return obj;

var entities = [];
var result = [];
result.totalResults = parseInt(obj.Entities['$'].TotalResults);

if(obj.Entities == undefined && obj.Entity == undefined) //If unknown result, return the object as is
return obj;
else if(obj.Entities == undefined){ //if only one entity
entities.push(obj.Entity);
result.totalResults = 1;
}else{
entities = obj.Entities.Entity;
result.totalResults = parseInt(obj.Entities['$'].TotalResults);
}

if(result.totalResults == 0)
return result;

obj.Entities.Entity.forEach(function(entity){

var convertedEntity = {
type: entity['$'].Type
};

entity.Fields[0].Field.forEach(function(field){
var name = field['$'].Name;
var value = field.Value ? field.Value[0] : null;
convertedEntity[name] = value;
});

result.push(convertedEntity);
});
entities.forEach(function(entity){
result.push( this.convertEntity(entity) );
}.bind(this));

if (result.totalResults == 1)
return result[0];
return result;
};

Expand All @@ -167,6 +183,12 @@ qcApi.prototype.buildUrl = function(url, options){
if(options.pageSize)
queryString.push('page-size=' + options.pageSize);

if (options.query)
queryString.push("query={" + options.query.join(';')+"}");

if(options.startIndex)
queryString.push('start-index=' + options.startIndex);

if(options.fields && options.fields.length != undefined)
queryString.push('fields=' + options.fields.join(','));

Expand Down Expand Up @@ -203,6 +225,19 @@ qcApi.prototype.get = function(url, options) {
return promise;
};

qcApi.prototype.objToXml = function(obj){
var convertedObj = { "$": {Type: (obj.type? obj.type: obj.Type)},
Fields:{Field:[]}};
Object.keys( obj ).forEach( function(prop){
if (prop == 'Type' || prop == 'type') return;
var value = obj[prop];
convertedObj.Fields.Field.push( {"$": {Name: prop}, "Value": value} );
});

var builder = new xml2js.Builder({rootName : 'Entity', attrkey : '$'});
var xml = builder.buildObject(convertedObj);
return xml;
};


module.exports = {
Expand Down