express-mesh
Version:
A Gentics Mesh frontend for Express.
320 lines (319 loc) • 13.7 kB
JavaScript
;
var http = require('http');
var Q = require('q');
var URL = require('url');
var u = require('./meshUtil');
var lang = require('./meshLanguages');
var mesh_1 = require("./mesh");
/**
* Mesh Rest response object
*/
var MeshRestResponse = (function () {
function MeshRestResponse(status, data, isBinary) {
this.status = status;
this.data = data;
this.isBinary = isBinary;
}
return MeshRestResponse;
})();
exports.MeshRestResponse = MeshRestResponse;
/**
* Possible authentication methods.
*/
(function (MeshAuthType) {
MeshAuthType[MeshAuthType["BASIC"] = 0] = "BASIC";
})(exports.MeshAuthType || (exports.MeshAuthType = {}));
var MeshAuthType = exports.MeshAuthType;
/**
* Mesh authentication obejct.
*/
var MeshAuth = (function () {
/**
* Initialize the Mesh authentication object.
* It generates the needed authentication header for making Mesh requests.
* @param request The MeshRequest
*/
function MeshAuth(request) {
this.type = MeshAuthType.BASIC;
if (u.isDefined(request.session[MeshAuth.MESH_USER_SESSION_KEY]) && u.isDefined(request.session[MeshAuth.MESH_PASSWORD_SESSION_KEY])) {
this.header = this.getBasicAuthHeader(request.session[MeshAuth.MESH_USER_SESSION_KEY], request.session[MeshAuth.MESH_PASSWORD_SESSION_KEY]);
}
else {
this.header = this.getBasicAuthHeader(request.meshConfig.publicUser.username, request.meshConfig.publicUser.password);
}
}
/**
* Generate basic auth header from username and password.
* @param username Username
* @param password Password
* @returns {string} Header string.
*/
MeshAuth.prototype.getBasicAuthHeader = function (username, password) {
return 'Basic ' + new Buffer(username + ':' + password).toString('base64');
};
MeshAuth.MESH_USER_SESSION_KEY = 'meshusername';
MeshAuth.MESH_PASSWORD_SESSION_KEY = 'meshpassword';
return MeshAuth;
})();
exports.MeshAuth = MeshAuth;
/**
* Options for making Mesh Requests.
*/
var MeshRequestOptions = (function () {
/**
* Initialize request options and prefill it with the authentication object.
* @param request MeshRequest
*/
function MeshRequestOptions(request) {
this.auth = new MeshAuth(request);
this.logging = request.meshConfig.logging;
}
return MeshRequestOptions;
})();
exports.MeshRequestOptions = MeshRequestOptions;
/**
* MeshRestClient that can be used to make requests to the mesh backend.
*/
var MeshRestClient = (function () {
function MeshRestClient() {
this.publicMeshCookieUserStore = {};
}
/**
*
* @param req
* @param path
* @param maxDepth
* @returns {Q.Promise<MeshRestResponse<IMeshNav>>}
*/
MeshRestClient.prototype.getNavigationByPath = function (req, path, params) {
var url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + req.meshConfig.navroot + path, params = params ? params : new mesh_1.MeshQueryParams();
params.maxDepth = params.maxDepth ? params.maxDepth : 10;
return this.meshSimpleGET(req, url, params).then(function (response) {
return response;
});
};
MeshRestClient.prototype.getNavigationByUUID = function (req, uuid, params) {
var url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + MeshRestClient.NODES_ENDPOINT + uuid + MeshRestClient.NAVIGATION_ENDPOINT, params = params ? params : new mesh_1.MeshQueryParams();
params.maxDepth = params.maxDepth ? params.maxDepth : 10;
return this.meshSimpleGET(req, url, params).then(function (response) {
return response;
});
};
MeshRestClient.prototype.getWebrootNode = function (req, params) {
var url = req.path;
if (typeof url === 'undefined' || u.getPath(url) === '/') {
url = req.meshConfig.index;
}
if (!params) {
params = req.query;
}
url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + req.meshConfig.webroot + url;
return this.meshSimpleGET(req, url, params).then(function (response) {
if (req.meshConfig.checkPublished && !response.isBinary && !response.data.published && response.status < 400) {
response.status = 404;
}
return response;
});
};
MeshRestClient.prototype.getMeshNode = function (req, uuid, params) {
var url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + MeshRestClient.NODES_ENDPOINT + uuid;
return this.meshSimpleGET(req, url, params).then(function (response) {
if (req.meshConfig.checkPublished && !response.isBinary && !response.data.published && response.status < 400) {
response.status = 404;
}
return response;
});
};
MeshRestClient.prototype.getChildren = function (req, uuid, params) {
var url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + MeshRestClient.NODES_ENDPOINT + uuid + "/children";
return this.meshSimpleGET(req, url, params);
};
MeshRestClient.prototype.meshSearch = function (req, query, params) {
var opts = new MeshRequestOptions(req), languages = lang.getLanguageArray(req);
opts.url = opts.url = req.meshConfig.backendUrl + req.meshConfig.base + 'search/nodes';
opts.params = params;
opts.params.resolveLinks = 'short';
if (params.lang) {
opts.params.lang = params.lang;
}
else if (u.isDefined(languages)) {
opts.params.lang = languages.join(',');
}
return this.meshPOST(opts, query);
};
MeshRestClient.prototype.getTagFamilies = function (req, params) {
var url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + MeshRestClient.TAG_FAMILIES_ENDPOINT;
return this.meshSimpleGET(req, url, params);
};
MeshRestClient.prototype.getTagsOfTagFamily = function (req, uuid, params) {
var url = req.meshConfig.backendUrl + req.meshConfig.base + req.meshConfig.project + MeshRestClient.TAG_FAMILIES_ENDPOINT + '/' + uuid + '/tags';
return this.meshSimpleGET(req, url, params);
};
MeshRestClient.prototype.login = function (req, username, password) {
var opts = new MeshRequestOptions(req);
opts.url = opts.url = req.meshConfig.backendUrl + req.meshConfig.base + 'auth/login';
return this.meshPOST(opts, {
"username": username,
"password": password
}).then(function (response) {
if (response.status === 200) {
return true;
}
else {
return false;
}
}).catch(function (err) {
return false;
});
};
MeshRestClient.prototype.logout = function (req) {
var opts = new MeshRequestOptions(req);
opts.url = opts.url = req.meshConfig.backendUrl + req.meshConfig.base + 'auth/logout';
return this.makeMeshRequest(opts).then(function (response) {
return true;
}).catch(function (err) {
return false;
});
};
MeshRestClient.prototype.meshSimpleGET = function (req, url, params) {
return this.meshSimpleRequest('GET', req, url, params);
};
MeshRestClient.prototype.meshSimpleRequest = function (method, req, url, params, data) {
var opts = new MeshRequestOptions(req), languages = lang.getLanguageArray(req);
if (u.isDefined(url)) {
if (url.indexOf(req.meshConfig.base) <= -1) {
url = req.meshConfig.base + url;
}
if (url.indexOf(req.meshConfig.backendUrl) <= -1) {
url = req.meshConfig.backendUrl + url;
}
}
opts.url = url;
opts.params = params ? params : new mesh_1.MeshQueryParams();
opts.params.resolveLinks = 'short';
opts.method = method;
opts.data = data;
if (u.isDefined(languages) && !opts.params.lang) {
opts.params.lang = languages.join(',');
}
return this.makeMeshRequest(opts);
};
MeshRestClient.prototype.meshPOST = function (requestOptions, data) {
requestOptions.method = 'POST';
requestOptions.data = data;
return this.makeMeshRequest(requestOptions);
};
/**
* Convert a queryParams object into a URL-encoded string.
*/
MeshRestClient.prototype.queryStringFromParams = function (queryParams) {
var queryString = '?';
for (var prop in queryParams) {
if (queryParams.hasOwnProperty(prop)) {
queryString += prop + '=' + encodeURIComponent(queryParams[prop]) + '&';
}
}
// return substring to remove trailing '&'
return queryString.substr(0, queryString.length - 1);
};
MeshRestClient.prototype.makeMeshRequest = function (requestOptions) {
var _this = this;
var deferred = Q.defer(), options = {}, urlString = requestOptions.url, url, data;
if (u.isDefined(requestOptions.params)) {
urlString += this.queryStringFromParams(requestOptions.params);
}
url = URL.parse(urlString);
options.host = url.host;
options.port = Number(url.port);
options.path = url.path;
options.hostname = url.hostname;
options.method = requestOptions.method ? requestOptions.method : 'GET';
options.headers = {};
if (u.isDefined(this.publicMeshCookieUserStore[requestOptions.auth.header])) {
options.headers['Cookie'] = this.publicMeshCookieUserStore[requestOptions.auth.header];
}
options.headers['Accept'] = '*/*';
if (u.isDefined(requestOptions.data)) {
data = JSON.stringify(requestOptions.data);
options.headers['Content-Type'] = 'application/json';
options.headers['Content-Length'] = Buffer.byteLength(data);
}
if (requestOptions.auth && requestOptions.auth.type === MeshAuthType.BASIC) {
options.headers['Authorization'] = requestOptions.auth.header;
}
var starttime = Date.now(), req = http.request(options, function (res) {
var data = '';
if (res.statusCode === 401 || res.statusCode === 403) {
console.error(res.statusCode, res.statusMessage, 'Check your mesh user.');
}
if (u.isDefined(res.headers) && u.isDefined(res.headers['set-cookie'])) {
res.headers['set-cookie'].forEach(function (cookie) {
var meshCookie;
if (cookie.indexOf('mesh.session') > -1) {
meshCookie = cookie.substring(0, cookie.indexOf(';'));
_this.publicMeshCookieUserStore[requestOptions.auth.header] = meshCookie;
}
});
}
if (u.isDefined(res.headers) && u.isDefined(res.headers['content-disposition'])) {
var response = new MeshRestResponse(res.statusCode, undefined, true);
response.stream = res;
deferred.resolve(response);
}
else {
res.on('data', function (chunk) {
data += chunk;
});
res.on('error', function (err) {
console.error(err);
});
res.on('end', function () {
try {
var result = JSON.parse(data);
if (requestOptions.logging.data) {
console.log(JSON.stringify(result, null, 4));
}
if (requestOptions.logging.timing) {
console.log('TIMING: ', options.path, (Date.now() - starttime) + 'ms');
}
if (result.error || result.success == 0) {
deferred.reject(new MeshRestResponse(res.statusCode, result.error || 'Unknown error', false));
}
else {
//DEBUG LOG FOR JSON NODES
deferred.resolve(new MeshRestResponse(res.statusCode, result, false));
}
}
catch (e) {
console.error('parse error');
e.parseError = 'Error while parsing json';
e.options = options;
deferred.reject(new MeshRestResponse(res.statusCode, e, false));
}
});
}
});
req.on('socket', function (socket) {
socket.setTimeout(30000);
socket.on('timeout', function () {
req.abort();
});
});
req.on('error', function (err) {
err.options = options;
console.error('ERROR IN REQUEST', err);
deferred.reject(new MeshRestResponse(u.STATUS_ERROR, err, false));
});
if (u.isDefined(data)) {
req.write(data);
}
req.end();
return deferred.promise;
};
MeshRestClient.NODES_ENDPOINT = '/nodes/';
MeshRestClient.NAVIGATION_ENDPOINT = '/navigation';
MeshRestClient.CHILDREN_ENDPOINT = '/children';
MeshRestClient.TAG_FAMILIES_ENDPOINT = '/tagFamilies';
return MeshRestClient;
})();
exports.MeshRestClient = MeshRestClient;