diff --git a/package.json b/package.json index bfa0e9619..fd234b5f0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "oauthd", "description": "OAuth that just works.", - "version": "1.0.0-alpha.8", + "version": "1.0.0-alpha.9", "homepage": "http://oauth-io.github.io/oauthd", "author": "OAuth team ", "repository": { diff --git a/providers/tripit/conf.json b/providers/tripit/conf.json index 350efc39e..5d43e2786 100644 --- a/providers/tripit/conf.json +++ b/providers/tripit/conf.json @@ -2,6 +2,9 @@ "name": "Tripit", "desc": "The TripIt API allows users to access the TripIt's information about travel and itineraries. TripIt facilitates integration and organization of travel information from many different sources. The TripIt API allows third parties to easily interface with this platform.", "url": "https://api.tripit.com", + "mobile": { + "url": "https://m.tripit.com" + }, "oauth1": { "request_token": "/oauth/request_token", "authorize": { diff --git a/src/cli/plugins.coffee b/src/cli/plugins.coffee index 53c7f1d53..6af79f0ca 100644 --- a/src/cli/plugins.coffee +++ b/src/cli/plugins.coffee @@ -81,8 +81,8 @@ module.exports = (args, options) -> installed = _installed console.log 'This instance has ' + (installed.length + ' installed plugin(s):').white - console.log (active.length + ' active plugin(s)').green - for name in active + console.log ((Object.keys(active)).length + ' active plugin(s)').green + for name, value of active console.log '- ' + name console.log (inactive.length + ' inactive plugin(s)').yellow for name in inactive @@ -249,50 +249,52 @@ module.exports = (args, options) -> if !plugin_data.name? return done null, null, true title = plugin_data.name?.white + ' ' - plugin_git = scaffolding.plugins.git(plugin_data.name, fetch) - text = plugin_data.description + "\n" if plugin_data.description? && plugin_data.description != "" - if not text? - text = 'No description\n' - plugin_git.getCurrentVersion() - .then (current_version) -> - if current_version.type == 'branch' - plugin_git.getVersionMask() - .then (mask) -> - update = '' - if not current_version.uptodate - update = ' (' + 'Updates available'.green + ')' - - if mask != current_version.version - update += ' (plugins.json points \'' + mask + '\')' - title += '(' +current_version.version + ')' + update + "" - - done(title, text) - else if current_version.type == 'tag_n' - plugin_git.getVersionMask() - .then (mask) -> - plugin_git.getLatestVersion(mask) - .then (latest_version) -> - + scaffolding.plugins.git(plugin_data.name, fetch) + .then (plugin_git) -> + text = plugin_data.description + "\n" if plugin_data.description? && plugin_data.description != "" + if not text? + text = 'No description\n' + plugin_git.getCurrentVersion() + .then (current_version) -> + if current_version.type == 'branch' + plugin_git.getVersionMask() + .then (mask) -> update = '' - if plugin_git.isNumericalVersion(latest_version) - if plugin_git.compareVersions(latest_version, current_version.version) > 0 - update = ' (' + latest_version.green + ' is available)' - else - update = ' (plugins.json points \'' + latest_version + '\')' + if not current_version.uptodate + update = ' (' + 'Updates available'.green + ')' + + if mask != current_version.version + update += ' (plugins.json points \'' + mask + '\')' title += '(' +current_version.version + ')' + update + "" done(title, text) - else if current_version.type == 'tag_a' - plugin_git.getVersionMask() - .then (mask) -> - title += '(tag ' + current_version.version + ')' - if (mask != current_version.version) - title += ' (plugins.json points \'' + mask + '\')' + else if current_version.type == 'tag_n' + plugin_git.getVersionMask() + .then (mask) -> + plugin_git.getLatestVersion(mask) + .then (latest_version) -> + update = '' + if plugin_git.isNumericalVersion(latest_version) + if plugin_git.compareVersions(latest_version, current_version.version) > 0 + update = ' (' + latest_version.green + ' is available)' + else + update = ' (plugins.json points \'' + latest_version + '\')' + title += '(' +current_version.version + ')' + update + "" + done(title, text) + else if current_version.type == 'tag_a' + plugin_git.getVersionMask() + .then (mask) -> + title += '(tag ' + current_version.version + ')' + if (mask != current_version.version) + title += ' (plugins.json points \'' + mask + '\')' + done(title, text) + else if current_version.type == 'unversionned' + title += "(unversionned)" done(title, text) - else if current_version.type == 'unversionned' - title += "(unversionned)" - done(title, text) + .fail (e) -> + done(title, text) .fail (e) -> - done(title, text) + if verbose + console.log 'Error with plugin \'' + name.white + '\':', e.message .fail (e) -> if verbose console.log 'Error with plugin \'' + name.white + '\':', e.message @@ -315,7 +317,8 @@ module.exports = (args, options) -> , options.fetch else scaffolding.plugins.info.getActive() - .then (names) -> + .then (plugins) -> + names = Object.keys plugins errors_found = false async.eachSeries names, (n, next) -> doGetInfo n, options.verbose?, (title, text, e) -> diff --git a/src/core/utilities/formatters.coffee b/src/core/utilities/formatters.coffee index a307a275c..656e17df9 100644 --- a/src/core/utilities/formatters.coffee +++ b/src/core/utilities/formatters.coffee @@ -17,7 +17,7 @@ restify = require 'restify' module.exports = (env) -> - + check = env.utilities.check config = env.config @@ -50,6 +50,8 @@ module.exports = (env) -> result.message = res.message result.data = body if typeof body == 'object' && Object.keys(body).length else + if res.statusCode < 200 or res.statusCode >= 300 + result.status = 'error' body = null if not body? result.data = body body = result @@ -96,4 +98,4 @@ module.exports = (env) -> formatters: formatters build: (e,r) -> buildReply e || r, buildJsend: true } - \ No newline at end of file + diff --git a/src/data/base-entity.coffee b/src/data/base-entity.coffee index deef4cebd..134958a70 100644 --- a/src/data/base-entity.coffee +++ b/src/data/base-entity.coffee @@ -7,6 +7,7 @@ module.exports = (env) -> class Entity @prefix: '' @incr: '' + @indexes: [] @findById: (id) -> defer = Q.defer() lapin = new @(id) @@ -16,6 +17,18 @@ module.exports = (env) -> .fail (e) -> defer.reject e defer.promise + @findByIndex: (field, index) -> + defer = Q.defer() + # looking for id + env.data.redis.hget @indexes[field], index, (err, id) => + return defer.reject err if err + entity = new @(id) + entity.load() + .then () -> + defer.resolve entity + .fail (e) -> + defer.reject e + defer.promise @onCreate: (entity) -> # creation additional operations @onUpdate: (entity) -> @@ -37,11 +50,12 @@ module.exports = (env) -> # asunc removal additional operations done() id: 0 # represents the entity in db + oldIndexesValues: {} props: {} # the entity's properties prefix: () -> # the prefix of the entity, e.g. user:23: @constructor.prefix + ':' + @id + ':' constructor: (id) -> - @id = id + @id = id keys: () -> defer = Q.defer() keys = {} @@ -100,18 +114,29 @@ module.exports = (env) -> defer = Q.defer() @getAll() .then (data) => - @props = data - defer.resolve(data) + if Object.keys(data).length > 0 + @props = data + defer.resolve(data) + else + defer.reject new Error('Data not found') .fail (e) -> defer.reject(e) defer.promise - save: (overwrite, delete_unknown_keys) -> - overwrite ?= true - delete_unknown_keys ?= false + # accepted values for opts: + # - overwrite: boolean - overwrite values, default true + # - del_unset - delete not set values, default false + # - ttl: time to live for entry, in seconds (from creation or update time) + save: (opts) -> + opts = opts || {} + overwrite = opts.overwrite + overwrite ?= true + + delete_unknown_keys = opts.del_unset + delete_unknown_keys ?= false defer = Q.defer() - + # hat function that actually saves _save = (done) => multi = env.data.redis.multi() @@ -125,25 +150,52 @@ module.exports = (env) -> for key in keys if key not in prefixedProps multi.del key - for key, value of @props - if typeof value == 'string' or typeof value == 'number' - multi.set @prefix() + key, value - else if typeof value == 'object' and Array.isArray(value) - multi.del @prefix() + key - for k, v of value - multi.sadd @prefix() + key, v - else if value? and typeof value == 'object' - if overwrite - multi.del @prefix() + key - multi.hmset @prefix() + key, value - else - # TODO (value instanceof Boolean || typeof value == 'boolean') - console.log "not saved: type not found" - - # actual save - multi.exec (e, res) => - return done e if e - done() + async.waterfall [ + # Managing indexes, removing unused values, and adding new values + (cb) => + index_keys = Object.keys(@constructor.indexes) + async.eachSeries index_keys, (key, ccb) => + index_key = key + index_field = @constructor.indexes[key] + env.data.redis.get @prefix() + index_key, (err, value) => + if not err and @props[index_key]? and value? != @props[index_key] + multi.hdel index_field, value + multi.hset index_field, @props[index_key], @id + if not value + multi.set @prefix() + index_key, @props[index_key] + ccb() + , () => + cb() + # Saving normal keys + (cb) => + for key, value of @props + # check if key is an index + index_field = @constructor.indexes[key] + if index_field? + if @oldIndexesValues[key]? and @oldIndexesValues[key] != value + multi.hdel index_field, @oldIndexesValues[key] + if typeof value == 'string' or typeof value == 'number' + multi.set @prefix() + key, value + else if typeof value == 'object' and Array.isArray(value) + multi.del @prefix() + key + for k, v of value + multi.sadd @prefix() + key, v + else if value? and typeof value == 'object' + if overwrite + multi.del @prefix() + key + multi.hmset @prefix() + key, value + else + # TODO (value instanceof Boolean || typeof value == 'boolean') + console.log "not saved: type not found" + if opts.ttl? + multi.expire @prefix() + key, opts.ttl + + cb() + ], () => + # Actual execution of the db access + multi.exec (e, res) => + return done e if e + done() .fail (e) => return done e if e @@ -171,22 +223,39 @@ module.exports = (env) -> return defer.reject e if e defer.resolve() - + defer.promise remove: () -> defer = Q.defer() multi = env.data.redis.multi() - @keys() - .then (keys) => - for key in keys - multi.del key - multi.exec (e) => - return defer.reject e if e - @constructor.onRemoveAsync @, (e) -> - return defer.reject e if e - defer.resolve() - .fail (e) => - defer.reject e + + async.waterfall [ + # first delete indexes + (next) => + index_keys = Object.keys @constructor.indexes + async.eachSeries index_keys, (key, next2) => + env.data.redis.get @prefix() + key, (err, index_value) => + if not err? and index_value? + multi.hdel @constructor.indexes[key], index_value + next2() + , () => + next() + # then delete normal keys + (next) => + @keys() + .then (keys) => + for key in keys + multi.del key + multi.exec (e) => + return defer.reject e if e + @constructor.onRemoveAsync @, (e) => + return defer.reject e if e + defer.resolve() + next() + .fail (e) => + defer.reject e + next() + ] defer.promise - Entity \ No newline at end of file + Entity diff --git a/src/presentationLayer/auth/index.coffee b/src/presentationLayer/auth/index.coffee index 0eaad65eb..1a3864865 100644 --- a/src/presentationLayer/auth/index.coffee +++ b/src/presentationLayer/auth/index.coffee @@ -266,15 +266,21 @@ module.exports = (env) -> ], (err, url) -> return callback err if err - #Fitbit needs this for mobile - if provider_conf.mobile?.params? and req.params.mobile == 'true' - for k,v of provider_conf.mobile.params - if url.indexOf('?') == -1 - url += '?' - else - url += '&' - url += k + '=' + v - + #Fitbit and tripit needs this for mobile + if provider_conf.mobile? + if provider_conf.mobile?.params? and req.params.mobile == 'true' + for k,v of provider_conf.mobile.params + if url.indexOf('?') == -1 + url += '?' + else + url += '&' + url += k + '=' + v + opts = JSON.parse(req.params.opts) + if opts.mobile is 'true' and provider_conf.mobile?.url? + url_split = url.split("/oauth/authorize") + if url_split.length is 2 + url = provider_conf.mobile.url + '/oauth/authorize/' + url_split[1] + res.setHeader 'Location', url res.send 302 next() diff --git a/src/scaffolding/plugins/info.coffee b/src/scaffolding/plugins/info.coffee index bdbbfb96a..aa288469e 100644 --- a/src/scaffolding/plugins/info.coffee +++ b/src/scaffolding/plugins/info.coffee @@ -76,7 +76,7 @@ module.exports = (env) -> info.getPluginsJson { activeOnly: true } .then (plugins) -> - defer.resolve Object.keys plugins + defer.resolve plugins .fail (e) -> defer.reject e @@ -111,8 +111,7 @@ module.exports = (env) -> installed_plugins = _installed return info.getActive() .then (_active) -> - active_plugins = _active - + active_plugins = Object.keys _active inactive_plugins = [] for plugin in installed_plugins if plugin not in active_plugins