Skip to content

Commit 337d861

Browse files
committed
Express skeleton, EJS templating, GD API library, working multproject invitations
1 parent 9337498 commit 337d861

File tree

10 files changed

+331
-0
lines changed

10 files changed

+331
-0
lines changed

TODO

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
* login
2+
* better error handling
3+
* visuals
4+
* setup gooddata#Client as subclass of http#Client
5+
* refactor rid the world of pesky "that"s

lib/gooddata.js

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
var http = require('http')
2+
,sys = require('sys');
3+
4+
5+
var HOSTNAME = 'secure.gooddata.com'
6+
,PORT = 443;
7+
8+
var acceptedCookies = ['GDCAuthSST','GDCAuthTT'];
9+
10+
11+
exports.createClient = function(debug) { return new Client(debug); };
12+
var Client = exports.Client = function Client(debug) {
13+
if (debug) this.debug = true;
14+
this.httpClient = http.createClient(PORT, HOSTNAME, (PORT === 443));
15+
this.data = { cookies: {}};
16+
};
17+
18+
Client.prototype.request = function(method, uri, postData, callback) {
19+
20+
if (!callback) { // shift arguments if there is no data
21+
callback = postData;
22+
postData = null;
23+
}
24+
25+
var headers = {
26+
'Host': HOSTNAME
27+
,'Accept': 'application/json'
28+
,'Content-Type': 'application/json; charset=utf-8'
29+
};
30+
31+
if (postData) {
32+
postData = JSON.stringify(postData);
33+
headers['Content-Length'] = postData.length;
34+
}
35+
36+
var cookies = this.sendCookies(this.data.cookies);
37+
if (cookies) {
38+
headers['Cookie'] = cookies;
39+
headers['X-GDC-AUTH'] = (this.data.cookies['GDCAuthTT']) ? this.data.cookies['GDCAuthTT'] : (this.data.cookies['GDCAuthSST']);
40+
}
41+
42+
var request = this.httpClient.request(method, uri, headers);
43+
44+
if (this.debug) {
45+
sys.debug('>>>> REQUEST');
46+
sys.debug(request._header);
47+
(postData) && sys.debug(postData);
48+
}
49+
if (postData) request.end(postData,'utf8');
50+
else request.end();
51+
52+
var data = '', that = this;
53+
request.on('response', function(response) {
54+
response.on('data', function(chunk) { data+=chunk; });
55+
response.on('end', function() {
56+
if (that.debug) {
57+
sys.debug('<<<< RESPONSE');
58+
sys.debug(response.statusCode);
59+
sys.debug(sys.inspect(response.headers));
60+
sys.debug(data);
61+
}
62+
63+
if (response.headers['content-type'] == 'application/json') data = JSON.parse(data);
64+
if (Array.isArray(response.headers['set-cookie'])) that.processSetCookie(response.headers['set-cookie']);
65+
callback(response, data);
66+
});
67+
});
68+
69+
};
70+
Client.prototype.get = function(uri, callback) { this.request('GET', uri, callback); };
71+
Client.prototype.post = function(uri, data, callback) { this.request('POST', uri, data, callback); };
72+
Client.prototype.login = function(username, password, callback) {
73+
var that = this;
74+
this.post('/gdc/account/login', {"postUserLogin":{"password":password,"login":username,"remember":"0"}}, function(res, data) {
75+
that.data['login'] = data.userLogin;
76+
that.getToken(callback);
77+
});
78+
};
79+
Client.prototype.getToken = function(callback) { this.get('/gdc/account/token', callback); };
80+
Client.prototype.listProjects = function(callback) {
81+
this.get(this.data.login.profile+'/projects', function(res, data) {
82+
callback(res, data.projects);
83+
});
84+
};
85+
Client.prototype.getProject = Client.prototype.get;
86+
Client.prototype.inviteIntoProject = function(project, users, role, callback) {
87+
role = role.toLowerCase() || 'editor';
88+
var that = this;
89+
this.get(project+'/roles', function(resp, data) { // find all roles in the project (returns just URIs)
90+
var roles = data.projectRoles.roles
91+
,rolesBody = {}
92+
,roleName = role;
93+
94+
var storeRole = function(uri) { // store role info when retrieved (and check if we have all roles already)
95+
return function(resp, data) {
96+
rolesBody[uri] = data;
97+
if (Object.keys(rolesBody).length == roles.length) findRole(rolesBody);
98+
};
99+
};
100+
101+
var findRole = function(roles) { // find role matching the name I'm looking for
102+
debugger;
103+
var filteredRoles = [];
104+
Object.keys(roles).forEach(function(role) {
105+
var roleObj = roles[role].projectRole;
106+
if (roleObj.meta.title.toLowerCase() == roleName.toLowerCase()) {
107+
roleObj.links.self = role;
108+
filteredRoles.push(roleObj);
109+
}
110+
});
111+
if (filteredRoles.length) { // if desired role is found, invite
112+
var body = { "invitations": []};
113+
users.forEach(function(user) {
114+
body['invitations'].push(
115+
{ "invitation": { "content": { "email": user, "role": filteredRoles[0].links.self, "firstname": "", "lastname": "", "action": { "setMessage": "some message" }}}}
116+
);
117+
});
118+
if (that.debug) sys.log('Sending invitation: '+JSON.stringify(body));
119+
that.post(project+'/invitations', body, function(resp, data) {
120+
if (resp.statusCode >= 200 && resp.statusCode < 300) {
121+
callback(false, resp, data);
122+
} else callback(true);
123+
});
124+
} else callback(true);
125+
};
126+
127+
roles.forEach(function(role) { // retrieve info for all roles in the project
128+
that.get(role, storeRole(role));
129+
});
130+
});
131+
};
132+
Client.prototype.processSetCookie = function(cookies) {
133+
var that = this;
134+
cookies.forEach(function(cookie) {
135+
parts = cookie.split(";")[0].split('=');
136+
if (acceptedCookies.indexOf(parts[0])!= -1) { // only accept certain cookies
137+
that.data['cookies'][parts[0].trim()]=parts[1].trim();
138+
}
139+
});
140+
};
141+
Client.prototype.sendCookies = function(cookies) {
142+
arr = [];
143+
144+
Object.keys(cookies).forEach(function(cookie) {
145+
arr.push(cookie+'='+cookies[cookie]);
146+
});
147+
if (arr.length) return arr.join('; ');
148+
else return false;
149+
};

public/css/style.css

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
body {
2+
padding: 50px;
3+
font: 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
4+
}

public/css/style.less

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
body {
2+
padding: 50px;
3+
font: 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
4+
}

public/js/modernizr-1.5.min.js

+28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
/**
3+
* Module dependencies.
4+
*/
5+
6+
var express = require('express')
7+
,connect = require('connect')
8+
,gooddata = require('./lib/gooddata')
9+
,sys = require('sys');
10+
11+
var app = module.exports = express.createServer();
12+
13+
// Configuration
14+
15+
app.configure(function(){
16+
app.set('views', __dirname + '/views');
17+
app.set('view engine', 'ejs');
18+
app.use(connect.bodyDecoder());
19+
app.use(connect.compiler({ src: __dirname + '/public', enable: ['less'] }));
20+
app.use(app.router);
21+
app.use(connect.staticProvider(__dirname + '/public'));
22+
});
23+
24+
app.configure('development', function(){
25+
app.use(connect.errorHandler({ dumpExceptions: true, showStack: true, textMateUrls: true }));
26+
});
27+
28+
app.configure('production', function(){
29+
app.use(connect.errorHandler());
30+
});
31+
32+
// Routes
33+
34+
app.get('/', function(req, res){
35+
36+
var gdc = gooddata.createClient();
37+
gdc.login('[email protected]', '', function(resp,data) {
38+
gdc.listProjects(function(resp, projects) {
39+
projects = projects.map(function(project) {
40+
if (project.project.meta.author == gdc.data.login.profile) project.project.meta['myProject'] = true;
41+
return project;
42+
});
43+
res.render('index', { locals: { projects: projects } });
44+
});
45+
});
46+
47+
});
48+
49+
app.post('/add', function(req, res) {
50+
var guests = req.body.guests;
51+
var projects = req.body.projects;
52+
53+
if (!guests || !Array.isArray(projects) || !projects.length) {
54+
throw new Error('You haven\' entered guest email address(es) or checked any projects!');
55+
}
56+
57+
guests = guests.split(',').map(function(guest) { return guest.trim(); });
58+
59+
var gdc = gooddata.createClient();
60+
gdc.login('[email protected]', '', function(resp,data) {
61+
projects.forEach(function(project) {
62+
gdc.inviteIntoProject(project, guests, 'editor', function(err, resp, data) {
63+
res.send('<code>'+sys.inspect(data,false,10)+'</code>');
64+
});
65+
});
66+
});
67+
});
68+
69+
// Only listen on $ node app.js
70+
71+
if (!module.parent) app.listen(3000);

0 commit comments

Comments
 (0)