Modularizes API.
Project: http://git-wip-us.apache.org/repos/asf/rave/repo Commit: http://git-wip-us.apache.org/repos/asf/rave/commit/fa312487 Tree: http://git-wip-us.apache.org/repos/asf/rave/tree/fa312487 Diff: http://git-wip-us.apache.org/repos/asf/rave/diff/fa312487 Branch: refs/heads/angular Commit: fa31248756c8b43dc796310404e27d6d331cbde5 Parents: 20b522c Author: Jmeas <[email protected]> Authored: Mon Aug 18 15:01:10 2014 -0400 Committer: Jmeas <[email protected]> Committed: Mon Aug 18 15:18:25 2014 -0400 ---------------------------------------------------------------------- .jshintrc-mock-api | 1 - rave-portal-ng/mock-api/bootstrap.js | 3 +- rave-portal-ng/mock-api/core.js | 37 ++++++++ .../mock-api/modules/preferences/db.js | 52 ++++++++++++ .../mock-api/modules/preferences/endpoint.js | 28 +++++++ .../mock-api/modules/preferences/get.js | 32 ------- .../mock-api/modules/preferences/index.js | 14 ++++ .../mock-api/modules/preferences/put.js | 56 ------------- rave-portal-ng/mock-api/modules/user/db.js | 54 ++++++++++++ rave-portal-ng/mock-api/util/endpoint.js | 88 ++++++++++++++++++++ rave-portal-ng/mock-api/util/error-response.js | 15 ++++ rave-portal-ng/mock-api/util/params.js | 37 ++++++++ rave-portal-ng/mock-api/util/token-util.js | 30 +++++++ 13 files changed, 356 insertions(+), 91 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/.jshintrc-mock-api ---------------------------------------------------------------------- diff --git a/.jshintrc-mock-api b/.jshintrc-mock-api index 754b84c..499a280 100644 --- a/.jshintrc-mock-api +++ b/.jshintrc-mock-api @@ -29,7 +29,6 @@ "unused" : "vars", "strict" : false, "trailing" : true, - "maxparams" : 4, "maxdepth" : 2, "asi" : false, http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/bootstrap.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/bootstrap.js b/rave-portal-ng/mock-api/bootstrap.js index 71e344b..92db321 100644 --- a/rave-portal-ng/mock-api/bootstrap.js +++ b/rave-portal-ng/mock-api/bootstrap.js @@ -37,8 +37,7 @@ define(function(require) { require('./modules/category/delete.js'); // preferences - require('./modules/preferences/get.js'); - require('./modules/preferences/put.js'); + require('./modules/preferences/index'); // users require('./modules/users/get.js'); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/core.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/core.js b/rave-portal-ng/mock-api/core.js index 780c32d..f782a7c 100644 --- a/rave-portal-ng/mock-api/core.js +++ b/rave-portal-ng/mock-api/core.js @@ -145,6 +145,42 @@ define(function(require) { return true; } + // Parse an endpoint for registration with the mock API. Eventually, + // this should be the only thing that's in the core. + function registerEndpoint(endpoint) { + + // Get our callback and url from the endpoint + var callback = endpoint.callback; + var url = endpoint.url; + + // The endpoint methods that we will register + var methods = ['get', 'put', 'post', 'delete']; + + // Register each method + _.each(methods, function(method) { + if (endpoint[method]) { + registerEndpointCallback(endpoint, url, method, callback); + } + }); + } + + // Once the endpoint has been parsed, we actually make the registration here + function registerEndpointCallback(endpoint, route, method, callback) { + if (!registeredApiMethods.hasOwnProperty(route)) { + registeredApiMethods[route] = { + pattern: convertRouteToRegex(baseApiUrl+route), + methods: {} + }; + } + + // Bind the callback to the endpoint + var moddedCallback = function(method, url, data, headers) { + return callback.bind(endpoint)(method, url, data, headers); + }; + + registeredApiMethods[route].methods[method.toUpperCase()] = moddedCallback; + } + function setSessionStorage(key, value) { try { value = JSON.stringify(value); @@ -171,6 +207,7 @@ define(function(require) { return { initialize: initializeApiModule, register: registerApiMethod, + registerEndpoint: registerEndpoint, db: database, session: { set: setSessionStorage, http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/modules/preferences/db.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/modules/preferences/db.js b/rave-portal-ng/mock-api/modules/preferences/db.js new file mode 100644 index 0000000..9d26997 --- /dev/null +++ b/rave-portal-ng/mock-api/modules/preferences/db.js @@ -0,0 +1,52 @@ +/* + * db + * Methods for getting and setting preferences data. Anytime + * you need to hit the DB in reference to preferences it should + * go through this file. + * + */ + +define(function(require) { + var api = require('../../core.js'); + + var prefsDb = { + + // Retrieve all of your preferences from the database. + // Although they're stored in the DB an array of objects with two + // properties each, key and value, this method transforms that data into an object. + get: function() { + var results = api.db.query('preferences'); + var preferences = {}; + + _.each(results, function(item) { + preferences[item.key] = item.value; + }); + + return preferences; + }, + + // Update the data in the database + put: function(data) { + var searchParams; + + // Loop through each value, updating it in the database + _.each(data, function(value, key) { + searchParams = { + key: key + }; + api.db.update('preferences', searchParams, function(row) { + row.value = value; + return row; + }); + }); + + // Save our data + api.db.commit(); + + // Lastly, return the updated data + return prefsDb.get(); + } + }; + + return prefsDb; +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/modules/preferences/endpoint.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/modules/preferences/endpoint.js b/rave-portal-ng/mock-api/modules/preferences/endpoint.js new file mode 100644 index 0000000..3696557 --- /dev/null +++ b/rave-portal-ng/mock-api/modules/preferences/endpoint.js @@ -0,0 +1,28 @@ +/* + * endpoint + * The actual endpoint for preferences + * + */ + +define(function(require) { + var Endpoint = require('../../util/endpoint'); + var prefsDb = require('./db'); + + var endpoint = new Endpoint({ + + url: '/preferences', + + // Our get endpoint. All that it does is return our + // of preferences as a simple object. + get: function(url, data, headers, params, currentUser) { + return [200, prefsDb.get()]; + }, + + // Puts our data into the database. + put: function(url, data, headers, params, currentUser) { + return [200, prefsDb.put(data)]; + } + }); + + return endpoint; +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/modules/preferences/get.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/modules/preferences/get.js b/rave-portal-ng/mock-api/modules/preferences/get.js deleted file mode 100644 index 4928b37..0000000 --- a/rave-portal-ng/mock-api/modules/preferences/get.js +++ /dev/null @@ -1,32 +0,0 @@ -define(function(require) { - 'use strict'; - - var api = require('../../core.js'); - require('underscore/underscore'); - - function getPreferences() { - var results = api.db.query('preferences'); - var preferences = {}; - - _.each(results, function(item) { - preferences[item.key] = item.value; - }); - - return preferences; - } - - function processRequest(method, url, data, headers) { - if (method !== 'GET') { - return [405, 'Unknown request']; - } else if (!this.requestHasToken) { - return [401, 'A valid token is required']; - } else if (!this.userIsAuthenticated) { - return [401, 'Invalid token']; - } - - return [200, getPreferences()]; - } - - api.register('/preferences', 'get', processRequest); - -} ); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/modules/preferences/index.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/modules/preferences/index.js b/rave-portal-ng/mock-api/modules/preferences/index.js new file mode 100644 index 0000000..58544ac --- /dev/null +++ b/rave-portal-ng/mock-api/modules/preferences/index.js @@ -0,0 +1,14 @@ +/* + * preferences + * Sets up the preferences section of the API. This includes two things: + * the actual endpoints and methods for retrieving data + * + */ + +define(function(require) { + var api = require('../../core.js'); + + // Register our endpoints + var endpoint = require('./endpoint'); + api.registerEndpoint(endpoint); +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/modules/preferences/put.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/modules/preferences/put.js b/rave-portal-ng/mock-api/modules/preferences/put.js deleted file mode 100644 index 845a894..0000000 --- a/rave-portal-ng/mock-api/modules/preferences/put.js +++ /dev/null @@ -1,56 +0,0 @@ -define(function(require) { - 'use strict'; - - var api = require('../../core.js'); - require('underscore/underscore'); - - function updatePreferences(data) { - var searchParams; - - // Loop through each data point, updating the corresponding preference - // in the database. - _.each(data, function(value, key) { - searchParams = { - key: key - }; - api.db.update('preferences', searchParams, function(row) { - row.value = value; - return row; - }); - }); - api.db.commit(); - - // This is exactly what we do in the GET method. We might - // want to DRY this up, but it's a mock API so no big deal. - var results = api.db.query('preferences'); - var preferences = {}; - - _.each(results, function(item) { - preferences[item.key] = item.value; - }); - - return preferences; - } - - function processRequest(method, url, data, headers) { - if (method !== 'PUT') { - return [405, 'Unknown request']; - } else if (!this.requestHasToken) { - return [401, 'A valid token is required']; - } else if (!this.userIsAuthenticated) { - return [401, 'Invalid token']; - } - - data = angular.fromJson(data); - - var updatedPreferences = updatePreferences(data); - if (!updatedPreferences) { - return [500, 'An internal database error has occurred']; - } - - return [200, updatedPreferences]; - } - - api.register('/preferences', 'put', processRequest); - -} ); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/modules/user/db.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/modules/user/db.js b/rave-portal-ng/mock-api/modules/user/db.js new file mode 100644 index 0000000..3dd351f --- /dev/null +++ b/rave-portal-ng/mock-api/modules/user/db.js @@ -0,0 +1,54 @@ +/* + * db + * Methods for getting and setting users. + * + */ + +define(function(require) { + var api = require('../../core.js'); + + // The whitelisted keys that we send back with our request for the users + var userKeys = [ + 'ID', + 'username', + 'description', + 'firstName', + 'lastName', + 'locked', + 'enabled', + 'expired', + 'authorities', + 'openIdUrl', + 'email' + ]; + + var userDb = { + + // Retrieve the user by an identifier + get: function(identifier, filter) { + + // Whether or not we want to filter the user's data. + // Filtering removes data we wouldn't want to send back, + // like passwords and tokens. Filtering is true by default + if (typeof filter === 'undefined') { + filter = true; + } + + var results = api.db.query('users', identifier); + + var user = results[0]; + + // If we don't have a user, then we return false + if (!user || results.length > 1) { + return false; + } + + // If we want to filter, then do it + user = filter ? _.pick(user, userKeys) : user; + + return user; + } + }; + + return userDb; +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/util/endpoint.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/util/endpoint.js b/rave-portal-ng/mock-api/util/endpoint.js new file mode 100644 index 0000000..9792164 --- /dev/null +++ b/rave-portal-ng/mock-api/util/endpoint.js @@ -0,0 +1,88 @@ +/* + * endpoint + * Defines a RESTful endpoint + * + */ + +define(function(require) { + var _ = require('underscore'); + var paramsFromUrl = require('./params'); + var ErrorResponse = require('./error-response'); + var tokenUtil = require('./token-util'); + var userDb = require('../modules/user/db'); + + // These are the valid options that you can pass into + // a new endpoint + var endpointOptions = [ + 'url', + 'authorize', + 'get', + 'post', + 'delete', + 'put' + ]; + + var Endpoint = function(options) { + + // Merge valid options directly into the endpoint + _.extend(this, _.pick(options, endpointOptions)); + }; + + _.extend(Endpoint.prototype, { + + // By default, all requests are + authorize: true, + + // What is ultimately returned from the endpoint. + callback: function(method, url, data, headers) { + + // Our current user, if there is one. + var currentUser; + + // The first thing we need to check for every endpoint is if we want to authorize or not + if (this.authorize) { + + // Attempt to get our token from the headers + var token = tokenUtil.tokenFromHeaders(headers); + + // If it doesn't exist, then we throw an error + if (!token) { + return new ErrorResponse(401, 'A valid token is required.'); + } + + // Otherwise, we try to get the user from the token + var user = userDb.get({ + sessionToken: token + }); + + // Again, throw an error if there's no user + if (!user) { + return new ErrorResponse(401, 'Invalid token.'); + } + + // Otherwise, we set our currentUser as the user. + currentUser = user; + } + + // Get our query parameters from the url + var params = paramsFromUrl(url); + + // Ensure that our method is lowercase + method = method.toLowerCase(); + + var callback = this[method]; + + // If we have the associated method, then we call it + if (_.isFunction(callback)) { + return callback(url, data, headers, params, currentUser); + } + + // Otherwise, this is an unhandled request. + else { + return new ErrorResponse(405, 'Unknown request'); + } + } + }); + + return Endpoint; +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/util/error-response.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/util/error-response.js b/rave-portal-ng/mock-api/util/error-response.js new file mode 100644 index 0000000..be1407b --- /dev/null +++ b/rave-portal-ng/mock-api/util/error-response.js @@ -0,0 +1,15 @@ +/* + * error + * A convenience class to generate a JSON error. + * + */ + +define(function(require) { + var ErrorResponse = function(code, msg) { + return [code, { + message: msg + }]; + }; + + return ErrorResponse; +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/util/params.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/util/params.js b/rave-portal-ng/mock-api/util/params.js new file mode 100644 index 0000000..2c0cbd9 --- /dev/null +++ b/rave-portal-ng/mock-api/util/params.js @@ -0,0 +1,37 @@ +/* + * params + * A function to generate the query parameters from a URL + * + */ + +define(function(require) { + + // Pass in the URL; get back your parameters. + return function(str) { + str = str.split('?')[1]; + if(typeof str !== 'string' || str.length === 0) { + return {}; + } + var s = str.split('&'); + var sLength = s.length; + var bit, query = {}, first, second; + for (var i = 0; i < sLength; i++) { + bit = s[i].split('='); + first = decodeURIComponent(bit[0]); + if(first.length === 0) { + continue; + } + second = decodeURIComponent(bit[1]); + if(typeof query[first] === 'undefined') { + query[first] = second; + } + else if(query[first] instanceof Array) { + query[first].push(second); + } + else { + query[first] = [query[first], second]; + } + } + return query; + }; +}); http://git-wip-us.apache.org/repos/asf/rave/blob/fa312487/rave-portal-ng/mock-api/util/token-util.js ---------------------------------------------------------------------- diff --git a/rave-portal-ng/mock-api/util/token-util.js b/rave-portal-ng/mock-api/util/token-util.js new file mode 100644 index 0000000..12dcdbb --- /dev/null +++ b/rave-portal-ng/mock-api/util/token-util.js @@ -0,0 +1,30 @@ +/* + * tokenUtil + * Utility methods for working with tokens. + * Eventually we will also generate tokens in here. + * + * + */ + +define(function(require) { + + var tokenUtil = { + + // Get the token from the headers. If it doesn't + // exist, or is invalid, then a value of false is returned + tokenFromHeaders: function(headers) { + if (!headers.Authorization) { + return false; + } + + var token = headers.Authorization.replace('Basic ', ''); + if (token.length !== 32) { + return false; + } + + return token; + } + }; + + return tokenUtil; +});
