Skip to content

Commit b8ee73a

Browse files
author
Hamlet Hakobyan
committed
Added support for copy, count, metadata, namedQuery, remove, report, search. Made some refactoring. Improved unit test coverage. Added examples for usage.
1 parent 71affe4 commit b8ee73a

36 files changed

+675
-89
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/dist/**

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
.vscode/
22
node_modules/
33
bower_components/
4+
dist/
5+
/o365.*

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@
22
A Workfront Stream API for AngularJS
33

44
Supported API version: 5.0, unsupported, internal
5+
6+
examples
7+
8+
run webpack-dev-server --host 127.0.0.1 --port 443 --content-base ./examples --devtool sourcemap --https --key o365.key --cert o365.crt
9+
set hosts 127.0.0.1 o365.attask-ondemand.com
10+
browse https://o365.attask-ondemand.com/index.html

examples/app.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* global angular */
2+
'use strict';
3+
4+
angular.module('testApp', ['streamApi'])
5+
.controller('testController', ['streamApiService', function(streamApiService) {
6+
this.doLogin = function() {
7+
var self = this;
8+
self.loginData = {};
9+
try {
10+
var streamApi = streamApiService.getInstance({url: self.host, version:'5.0'});
11+
} catch(e) {
12+
self.loginData = e.message;
13+
}
14+
15+
streamApi.login(self.username, self.password)
16+
.then(function(response) {
17+
self.loginData.loginData = response.data;
18+
var params = {};
19+
params['name'] = 'task ^&%$#@!~`';
20+
// params['status' + streamApi.Constants.MOD] = streamApi.Constants.Operators.NOTEQUAL;
21+
params[streamApi.Constants.LIMIT] = 1;
22+
return streamApi.search('task', params, 'ID');
23+
})
24+
.then(function(response) {
25+
self.loginData.searchedTask = response.data;
26+
var params = {};
27+
params['status'] = 'NEW';
28+
// params['status' + streamApi.Constants.MOD] = streamApi.Constants.Operators.NOTEQUAL;
29+
params[streamApi.Constants.LIMIT] = 1;
30+
return streamApi.search('project', params, 'ID');
31+
})
32+
.then(function(response) {
33+
self.loginData.projectData = response.data;
34+
var data = {
35+
name: 'Task created by angular-stream-api',
36+
projectID: response.data.data[0].ID
37+
};
38+
return streamApi.create('task', data);
39+
})
40+
.then(function(response) {
41+
self.loginData.createdTask = response.data;
42+
var actionArgs = {
43+
userIDs: [streamApi.Constants.WildCards.USER],
44+
roleIDs: []
45+
};
46+
return streamApi.execute('task', response.data.data.ID, 'assignMultiple', actionArgs);
47+
})
48+
.then(function(response) {
49+
self.loginData.assignedTask = response.data;
50+
return streamApi.execute('task', response.data.data.ID, 'markDone');
51+
})
52+
.then(function(response) {
53+
self.loginData.doneTask = response.data;
54+
})
55+
.catch(function(error) {
56+
self.loginData.error = error;
57+
});
58+
};
59+
}]);

examples/index.html

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head lang="en">
4+
<meta charset="UTF-8">
5+
<title>Login example</title>
6+
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
7+
8+
<!-- The script below is not needed if your browser supports ES6 promises -->
9+
10+
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
11+
<script src="../dist/angular-stream-api.js"></script>
12+
<script src="app.js"></script>
13+
</head>
14+
<body ng-app="testApp">
15+
<div class="container">
16+
<div ng-controller="testController as vm">
17+
<div class="form-group">
18+
<label for="url">Url</label>
19+
<input type="text" class="form-control" id="url" ng-model="vm.host" placeholder="Url to use for connection to Workfront">
20+
</div>
21+
22+
<div class="form-group">
23+
<label for="username">Username</label>
24+
<input type="text" class="form-control" id="username" ng-model="vm.username" placeholder="Your Workfront login">
25+
</div>
26+
<div class="form-group">
27+
<label for="password">Password</label>
28+
<input type="text" class="form-control" id="password" ng-model="vm.password" placeholder="Your Workfront password">
29+
</div>
30+
<div class="form-group">
31+
<label for="login-data">Login Data</label>
32+
<textarea id="login-data">{{vm.loginData | json}}</textarea>
33+
</div>
34+
35+
<button type="submit" class="btn btn-default" ng-click="vm.doLogin()">Login</button>
36+
</div>
37+
</div>
38+
</body>
39+
</html>

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"karma-webpack": "^1.7.0",
3636
"phantomjs-prebuilt": "^2.1.7",
3737
"url-parse": "^1.1.1",
38-
"webpack": "^1.13.1"
38+
"webpack": "^1.13.1",
39+
"webpack-dev-server": "^1.14.1"
3940
}
4041
}

src/ApiServiceProvider.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ function streamApiServiceProvider() {
77
this.$get = streamApiServiceFactory;
88
}
99

10-
streamApiServiceFactory.$inject = ['$http', '$q'];
11-
function streamApiServiceFactory($http, $q) {
10+
streamApiServiceFactory.$inject = ['$http', '$httpParamSerializer', '$q'];
11+
function streamApiServiceFactory($http, $httpParamSerializer, $q) {
1212
var Api = require('./service/Api'),
1313
factory = {},
1414
_instance;
1515

1616
Api.prototype.http = $http;
17+
Api.prototype.serializer = $httpParamSerializer;
1718
Api.prototype.promise = $q;
1819

1920
factory.getInstance = function(config, returnNewInstance) {

src/service/Api.js

+5
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,10 @@ require('./edit')(Api);
4747
require('./login')(Api);
4848
require('./logout')(Api);
4949
require('./execute')(Api);
50+
require('./search')(Api);
51+
require('./metadata')(Api);
52+
require('./namedQuery')(Api);
53+
require('./report')(Api);
54+
require('./remove')(Api);
5055

5156
module.exports = Api;

src/service/copy.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
module.exports = function(Api) {
44
Api.prototype.copy = function (objCode, objID, updates, fields) {
5+
if(!objCode || !objID) {
6+
throw new Error('You must provide at least objCode and objID');
7+
}
58
var params = {
69
copySourceID: objID
710
};
8-
11+
912
return this.request(objCode, updates, params, fields, this.Methods.POST);
1013
};
1114
};

src/service/count.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
module.exports = function(Api) {
44
Api.prototype.count = function(objCode, query) {
5+
if(!objCode) {
6+
throw new Error('You must provide \'objCode\'');
7+
}
58
var path = objCode + '/count';
6-
return this.request(path, null, query, null, this.Methods.GET)
9+
return this.request(path, undefined, query, undefined, this.Methods.GET)
710
.then(function(response) {
811
if(response.data && response.data.count) {
912
return response.data.count;

src/service/create.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
'use strict';
22

33
module.exports = function(Api) {
4+
45
Api.prototype.create = function(objCode, data, fields) {
5-
return this.request(objCode, data, null, fields, this.Methods.POST);
6+
if(!objCode || !data) {
7+
throw new Error('You must provide at least objCode and data');
8+
}
9+
return this.request(objCode, data, undefined, fields, this.Methods.POST);
610
};
711
};

src/service/edit.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ var angular = require('angular');
44

55
module.exports = function(Api) {
66
Api.prototype.edit = function(objCode, objID, data, fields) {
7-
if(!data) {
8-
throw new Error('You should pass edit data as \'data\' argument');
7+
if(!objCode || typeof objCode !== 'string') {
8+
throw new Error('You must provide objCode of type string');
99
}
10-
if(angular.isObject(objID) && ('ID' in objID)) {
11-
angular.extend(data, objID);
12-
} else if(typeof objID === 'string') {
13-
data.ID = objID;
10+
if(!data || !angular.isObject(data)) {
11+
throw new Error('You must provide edit data object as \'data\' argument');
12+
}
13+
if(!objID || typeof objID !== 'string') {
14+
if(!('ID' in data)) {
15+
throw new Error('You must provide either \'ojbID\' of type string or \'data\' with property ID');
16+
}
1417
} else {
15-
throw new Error('You should pass \'objID\' as a string or object with property \'ID\'');
18+
data.ID = objID;
1619
}
17-
return this.request(objCode, data, null, fields, this.Methods.PUT);
20+
return this.request(objCode, data, undefined, fields, this.Methods.PUT);
1821
};
1922
};

src/service/execute.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ module.exports = function(Api) {
1010
actionArgs = actionArgs || {};
1111
actionArgs['action'] = action;
1212
}
13-
return this.request(endPoint, actionArgs, null, this.Methods.PUT);
13+
return this.request(endPoint, undefined, actionArgs, undefined, this.Methods.PUT);
1414
};
1515
};

src/service/get.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ module.exports = function(Api) {
1313
};
1414
}
1515

16-
return this.request(objCode, null, params, fields, this.Methods.GET);
16+
return this.request(objCode, undefined, params, fields, this.Methods.GET);
1717
};
1818
};

src/service/login.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ module.exports = function(Api) {
77
password: password
88
};
99

10-
this.request('login', null, params, null, this.Methods.POST)
10+
return this.request('login', undefined, params, undefined, this.Methods.POST)
1111
.then(function(response) {
1212
if(response.data && response.data.data) {
13-
this.options.sessionID = response.data.data.sessionID;
14-
return response.data.data;
13+
this.options.headers = {sessionID: response.data.data.sessionID};
14+
return response.data;
1515
}
1616

1717
return this.promise.reject();

src/service/logout.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
module.exports = function(Api) {
44
Api.prototype.logout = function() {
5-
return this.request('logout', null, null, null, this.Methods.GET)
5+
return this.request('logout', undefined, undefined, undefined, this.Methods.GET)
66
.then(function(response) {
77
if(response.data && response.data.success) {
8-
delete this.options.sessionID;
8+
delete this.options.headers.sessionID;
99
return this.promise.resolve();
1010
}
1111

src/service/metadata.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
module.exports = function(Api) {
4+
Api.prototype.metadata = function (objCode) {
5+
var path = '/metadata';
6+
if (objCode) {
7+
path = objCode + path;
8+
}
9+
return this.request(path, undefined, undefined, undefined, this.Methods.GET);
10+
};
11+
};

src/service/namedQuery.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use strict';
2+
3+
module.exports = function(Api) {
4+
Api.prototype.namedQuery = function(objCode, queryName, queryArgs, fields) {
5+
var path = objCode + '/' + queryName;
6+
return this.request(path, undefined, queryArgs, fields, this.Methods.GET);
7+
};
8+
};

src/service/remove.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
module.exports = function(Api) {
4+
Api.prototype.remove = function(objCode, objID, force) {
5+
var path = objCode + '/' +objID;
6+
var params = force ? {force: true} : undefined;
7+
this.request(path, undefined, params, undefined, this.Methods.DELETE)
8+
.then(function(result) {
9+
if (result && result.success) {
10+
this.promise.resolve();
11+
} else {
12+
this.promise.reject();
13+
}
14+
}.bind(this));
15+
};
16+
};

src/service/report.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use strict';
2+
3+
module.exports = function(Api) {
4+
Api.prototype.report = function(objCode, query) {
5+
var path = objCode + '/report';
6+
return this.request(path, undefined, query, undefined, this.Methods.GET);
7+
};
8+
};

src/service/request.js

+27-17
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,47 @@ var angular = require('angular');
44

55
module.exports = function(Api) {
66
Api.prototype.request = function(path, data, params, fields, method) {
7+
if(data && method !== this.Methods.POST && method !== this.Methods.PUT) {
8+
throw new Error('You must specify method PUT or POST in case you have passed \'data\'');
9+
}
10+
11+
if(method === this.Methods.POST && !data && path !== 'login') {
12+
throw new Error('You must specify \'data\' in case you have used POST');
13+
}
14+
15+
fields = fields || [];
16+
if(typeof fields === 'string') {
17+
fields = [fields];
18+
}
19+
720
this.config = {};
821
this.config = angular.extend({}, this.options);
922

1023
var fullPath = path.indexOf('/') === 0 ? path : '/' + path;
1124
this.config.url = this.config.url + fullPath;
1225

13-
fields = fields || [];
14-
if(typeof fields === 'string') {
15-
fields = [fields];
26+
params = params || {};
27+
if(fields.length !== 0) {
28+
params.fields = fields.join();
1629
}
17-
30+
this.config.params = params;
1831
this.config.method = method;
19-
if(method === this.Methods.POST || method === this.Methods.PUT) {
20-
if(!data && path !== 'login') {
21-
throw new Error('You must specify \'data\' in case you have used PUT or POST');
22-
}
2332

33+
if( method === this.Methods.GET
34+
&& (( this.config.url + '?'+ this.serializer(params)).length > 2000
35+
|| path === 'batch' )) {
36+
this.config.method = this.Methods.POST;
37+
params.method = this.Methods.GET;
38+
this.config.data = params;
39+
this.config.params = undefined;
40+
this.config.headers = this.config.headers || {};
41+
this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
42+
} else if(data) {
2443
this.config.data = data;
2544
this.config.headers = this.config.headers || {};
2645
this.config.headers['Content-Type'] = 'application/json;charset=utf-8';
27-
} else if(data && path !== 'login') {
28-
throw new Error('You must specify method PUT or POST in case have passed \'data\'');
29-
}
30-
31-
params = params || {};
32-
if(fields.length !== 0) {
33-
params.fields = fields.join();
3446
}
3547

36-
this.config.params = params;
37-
3848
return this.http(this.config);
3949
};
4050
};

src/service/search.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use strict';
2+
3+
module.exports = function(Api) {
4+
Api.prototype.search = function(objCode, params, fields) {
5+
var endPoint = objCode + '/search';
6+
return this.request(endPoint, undefined, params, fields, this.Methods.GET);
7+
};
8+
};

0 commit comments

Comments
 (0)