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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules/
.idea/*
69 changes: 38 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ In your NodeJS program, add:

``` javascript
var tp = require('tp-api')({
domain: // your domain here; eg: 'fullscreen.tpondemand.com'
username: // your username; eg: '[email protected]'
password: // your password
version: // Optional API version - defaults to 1
protocol: // Optional protocol - defaults to https
})
domain: // your domain here; eg: 'fullscreen.tpondemand.com'
username: // your username; eg: '[email protected]'
password: // your password
version: // Optional API version - defaults to 1
protocol: // Optional protocol - defaults to https,
convertJsonDates: true // Optional convert all dates ((string) `/Date(1467210530000+0200)/`) returned by API to JS Date-Objects
})

tp('Tasks')
.take(5)
Expand Down Expand Up @@ -144,35 +145,41 @@ tp('Tasks').
})
```

#### Nested JSON objects
It may happen that the following code:
```javascript
tp('Tasks')
.take(1)
.pluck('CustomFields')
.then(function(err, tasks) {
console.log('my tasks', tasks)
}
)
## Hint
Some of these methods will return deeply nested objects. If you want to debug them it's recommended to use node's [`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
```
will return a lot of nested JSON objects:
```bash
my tasks [ { ResourceType: 'Task',
Id: 3631,
Project: { ResourceType: 'Project', Id: 4026, Process: [Object] },
CustomFields: [ [Object], [Object], [Object], [Object], [Object] ] } ]
```
The returned object `tasks` here is a JavaScript object. In order to convert it into JSON string, use [`JSON.stringify()`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify):
```javascript
var util = require('util');
tp('Tasks')
.take(1)
.pluck('CustomFields')
.take(10)
.then(function(err, tasks) {
console.log('my tasks', JSON.stringify(tasks)) // changed here
console.log(util.inspect(tasks, { showHidden: true, depth: null }));
}
)
```
and now it returns:
```bash
my tasks [{"ResourceType":"Task","Id":3631,"Project":{"ResourceType":"Project","Id":4026,"Process":{"Id":5,"Name":"AIScrum"}},"CustomFields":[{"Name":"Component","Type":"DropDown","Value":null},{"Name":"trac","Type":"Number","Value":null},{"Name":"Job","Type":"DropDown","Value":null},{"Name":"Resolution","Type":"DropDown","Value":null},{"Name":"Domain","Type":"DropDown","Value":null}]}]

## Changelog

### Version 1.3.0
Starting from this version you can return real [Date-Objects](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Date) if `convertJsonDates` is set to `true`
``` javascript
var tp = require('tp-api')({
domain: 'domain.tld',
token: 'abc'
convertJsonDates: true
});
tp('Tasks')
.take(3)
.pluck('Name', 'StartDate')
.then((err, tasks) => {
if (err) return console.log('err', err);
tasks.forEach(function(t) {
console.log( t.Id + ' :: ' + (t.StartDate.getMonth() + 1) + '-' + t.StartDate.getDate() + '-' + t.StartDate.getFullYear() + ' :: ' + t.Name );
/*
Outputs:
85299 :: 12-8-2015 :: Task 1
100853 :: 6-14-2016 :: Task 2
85708 :: 1-4-2016 :: Task 3
*/
})
});
```
9 changes: 1 addition & 8 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
var request = require('request')
var _ = require('lodash')
var TPQuery = require('./lib/tpquery')
var TPEntity= require('./lib/tpentity')
Expand All @@ -17,14 +16,8 @@ function configure(opts) {
throw new Error('A TargetProcess domain is required')
}

var version = opts.version || 1
var domain = opts.domain
var token = opts.token
var protocol = opts.protocol || 'https'
var urlRoot = protocol + '://'+domain+'/api/v'+version

return function(entity, id) {
var collection = new TPQuery(urlRoot, token)
var collection = new TPQuery(opts)
, model

if (entity) { collection.get(entity) }
Expand Down
16 changes: 11 additions & 5 deletions lib/tpentity.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ function TPEntity(data, options) {
}
}

TPEntity.prototype.fetch = function(cb) {
this.then({
method: 'GET',
uri: this.opts.uri + '/' + this.Id
}, cb)
}

TPEntity.prototype.create = function(data, cb) {
this.then({
json: data,
Expand Down Expand Up @@ -44,7 +51,7 @@ TPEntity.prototype.setState = function(stateName, cb) {
uri: this.baseUrl + '/EntityStates',
method: 'GET',
// force build a query for our current entity state
qs: {
qs: {
where: 'Id eq ' + this.EntityState.Id,
include: '[NextStates]'
},
Expand Down Expand Up @@ -78,6 +85,7 @@ TPEntity.prototype.sync = function(data){
* @return {Object} TPEntity
*/
TPEntity.prototype.then = function(opts, cb) {
if(!cb) { cb = noop }
opts.json = _.extend({}, opts.json || {})
if( this.Id ) {
// mixing in id so TP will be able to get the right object
Expand All @@ -87,12 +95,10 @@ TPEntity.prototype.then = function(opts, cb) {
var that = this
TPSync(options, function(err, data){
if( err ) {
return err;
return cb(err);
}
that.sync(data);
if( cb ) {
cb(err, data);
}
cb(err, data);
});
}

Expand Down
31 changes: 24 additions & 7 deletions lib/tpquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ var _ = require('lodash')

// TP Entity Query
// ----------------------
function TPQuery(baseUrl, token) {
this.baseUrl = baseUrl
function TPQuery(opts) {
this.version = opts.version || 1
this.domain = opts.domain
this.token = opts.token
this.protocol = opts.protocol || 'https'
this.baseUrl = this.protocol + '://' + this.domain + '/api/v' + this.version
this.opts = {
json: true,
qs: { token: token },
headers: { Authorization: 'Basic '+ token }
convertJsonDates: opts.convertJsonDates,
qs: { token: this.token },
headers: {
Authorization: 'Basic '+ this.token
}
}
}

Expand All @@ -23,7 +29,6 @@ TPQuery.prototype.entities = [

TPQuery.prototype.get = function(entity) {
this.opts = _.extend({}, this.opts, {
json: true,
uri: this.baseUrl+'/'+entity
})
return this;
Expand Down Expand Up @@ -89,7 +94,6 @@ TPQuery.prototype.append = function() {
*/
TPQuery.prototype.then = function(cb) {
var opts = this.opts
var that = this
TPSync(opts, function(err, data){
cb(err, data);
})
Expand Down Expand Up @@ -132,4 +136,17 @@ TPQuery.prototype.comment = function(entityId, comment, cb) {
}, cb)
}

TPQuery.prototype.tag = function(entityId, tags, cb) {
var that = this
var commentEntity = new TPEntity({}, that.opts)
commentEntity.then({
json: {
Id: entityId,
Tags: tags
},
uri: that.baseUrl + '/UserStories',
method: 'POST'
}, cb)
}

module.exports = TPQuery
37 changes: 30 additions & 7 deletions lib/tpsync.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
request = require('request')
var request = require('request');
var dotNetDate = require('json-dotnet-date')({
useInputTimeZone: true
});

var jsonReviver = function(key, value) {
if (dotNetDate.testStr(value)) {
return dotNetDate.parse(value);
}
return value;
}

function TPSync(opts, cb) {
return request(opts, function(err, res, json) {
if (typeof json === 'string') {
err = new Error("Couldn't find resource at "+ opts.uri)
// (Re)set options for request
opts.json = false;
opts.headers['content-type'] = 'application/json';

return request(opts, function(err, res, body) {
// TP returns XML in case of errors. Yay. ¯\_(ツ)_/¯
if (body.indexOf('<Error>') === 0) {
err = new Error('Couldn\'t find resource at ' + opts.uri + ' ' + JSON.stringify(opts.qs));
cb(err, null);
return;
}

var json = null;
try {
json = JSON.parse(body, opts.convertJsonDates ? jsonReviver : null);
} catch (e) {
err = new Error("Can't parse JSON: \n" + body);
}

if (json && json.Error) {
Expand All @@ -13,12 +37,11 @@ function TPSync(opts, cb) {
if (typeof err === 'string') {
err = new Error(err)
}

// normalize reponse data
if (json && json.Items) { json = json.Items }

cb(err, (err) ? null : json)
})
}

module.exports = TPSync
module.exports = TPSync
12 changes: 7 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tp-api",
"version": "1.2.1",
"version": "1.3.0",
"description": "An API to access entities from TargetProcess",
"main": "index.js",
"scripts": {
Expand All @@ -10,15 +10,17 @@
"contributors": [
"Ryan Barry <[email protected]> (https://github.com/ryancbarry)",
"Jeff Uyeno <[email protected]> (https://github.com/jeffuyeno)",
"Julian Kleinhans <[email protected]> (http://blog.kj187.de)"
"Julian Kleinhans <[email protected]> (http://blog.kj187.de)",
"Mathias Schopmans <[email protected]> (http://aoe.com)"
],
"license": "BSD",
"dependencies": {
"request": "~2.27.0",
"lodash": "~2.4.1"
"json-dotnet-date": "^0.1.7",
"lodash": "~4.16.4",
"request": "~2.76.0"
},
"devDependencies": {
"mocha": "~1.17.0"
"mocha": "~3.1.2"
},
"repository": {
"type": "git",
Expand Down