diff --git a/src/server/serverRoutes.coffee b/src/server/serverRoutes.coffee index 5b5235eba4..ba5fc05d7c 100644 --- a/src/server/serverRoutes.coffee +++ b/src/server/serverRoutes.coffee @@ -12,35 +12,37 @@ module.exports = (expressApp, root, derby) -> expressApp.get '/terms', (req, res) -> staticPages.render 'terms', res - # ---------- REST API ------------ + # ---------- Deprecated Paths ------------ - # Deprecated API (will remove soon) - deprecatedMessage = 'This REST resource is no longer supported, use /users/:uid/tasks/:taskId/:direction instead.' - expressApp.get '/:uid/up/:score?', (req, res) -> - res.send(200, deprecatedMessage) - expressApp.get '/:uid/down/:score?', (req, res) -> - res.send(200, deprecatedMessage) + deprecatedMessage = 'This API is no longer supported, see https://github.com/lefnire/habitrpg/wiki/API for new protocol' + expressApp.get '/:uid/up/:score?', (req, res) -> res.send(500, deprecatedMessage) + expressApp.get '/:uid/down/:score?', (req, res) -> res.send(500, deprecatedMessage) + expressApp.post '/v1/users/:uid/tasks/:taskId/:direction', (req, res) -> res.send(500, deprecatedMessage) - # New API - # test with `curl -X POST -H "Content-Type:application/json" localhost:3000/users/{uid}/tasks/productivity/up` - expressApp.post '/users/:uid/tasks/:taskId/:direction', (req, res) -> + # ---------- v1 API ------------ + + ### + v1 API. Requires user-id and api_token, task-id, direction. Test with: + curl -X POST -H "Content-Type:application/json" -d '{"api_token":"{TOKEN}"}' localhost:3000/v1/users/{UID}/tasks/productivity/up + ### + expressApp.post '/v1/users/:uid/tasks/:taskId/:direction', (req, res) -> {uid, taskId, direction} = req.params - {title, service, icon} = req.body + {api_token, title, service, icon} = req.body console.log {params:req.params, body:req.body} if process.env.NODE_ENV == 'development' # Send error responses for improper API call + return res.send(500, 'request body "api_token" required') unless api_token return res.send(500, ':uid required') unless uid return res.send(500, ':taskId required') unless taskId return res.send(500, ":direction must be 'up' or 'down'") unless direction in ['up','down'] model = req.getModel() - model.fetch "users.#{uid}", (err, user) -> + model.fetch model.query('users').withIdAndToken(uid, api_token), (err, result) -> return res.send(500, err) if err + user = result.at(0) userObj = user.get() - # Server crashes without this, I think some users are entering non-guid userIds and/or trying to use the API without having an account - unless userObj && !_.isEmpty(userObj.stats) - console.log {taskId:taskId, direction:direction, user:userObj, error: 'non-user attempted to score'} if process.env.NODE_ENV == 'development' - return res.send(500, "User #{uid} not found") + if _.isEmpty(userObj) + return res.send(500, "User with uid=#{uid}, token=#{api_token} not found. Make sure you're not using your username, but your User Id") model.ref('_user', user) diff --git a/src/server/store.coffee b/src/server/store.coffee index a7dedfaafb..8c786be279 100644 --- a/src/server/store.coffee +++ b/src/server/store.coffee @@ -14,4 +14,17 @@ module.exports = (store) -> return unless @session and @session.userId # https://github.com/codeparty/racer/issues/37 next = arguments[arguments.length - 1] isServer = not @req.socket - next(isServer) \ No newline at end of file + next(isServer) + + ### + Get user with API token + ### + store.query.expose "users", "withIdAndToken", (id, api_token) -> + @where("id").equals(id) + .where('preferences.api_token').equals(api_token) + .limit(1) + + store.queryAccess "users", "withIdAndToken", (id, token, next) -> + return next(false) unless @session and @session.userId # https://github.com/codeparty/racer/issues/37 + isServer = not @req.socket + next(isServer) diff --git a/views/app/index.html b/views/app/index.html index f9bd1f0309..82c0e7e7da 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -8,10 +8,15 @@ {#if _loggedIn} - User ID
- Copy this ID for use in third party applications. -
{_user.id}

+

API

+ Copy these for use in third party applications. +
User ID
+
{_user.id}
+
API Token
+
{_user.preferences.api_token}
+ +

Gender