mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-08-05 03:52:14 +00:00
Merge branch 'master' into notifications
This commit is contained in:
commit
4db3216e1d
11 changed files with 490 additions and 109 deletions
|
|
@ -23,8 +23,10 @@
|
|||
"mongoskin": "*",
|
||||
"nconf": "*",
|
||||
"icalendar": "git://github.com/lefnire/node-icalendar#master",
|
||||
"superagent": "~0.12.4",
|
||||
"resolve": "~0.2.3",
|
||||
"browserify": "1.17.3",
|
||||
"expect.js": "~0.2.0",
|
||||
"webkit-devtools-agent": "*"
|
||||
},
|
||||
"private": true,
|
||||
|
|
@ -38,6 +40,7 @@
|
|||
"npm": "1.1.x"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "server.js"
|
||||
"start": "server.js",
|
||||
"test": "mocha test/api.mocha.coffee"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,56 +3,116 @@ router = new express.Router()
|
|||
|
||||
scoring = require '../app/scoring'
|
||||
_ = require 'underscore'
|
||||
icalendar = require('icalendar')
|
||||
validator = require 'derby-auth/node_modules/validator'
|
||||
check = validator.check
|
||||
sanitize = validator.sanitize
|
||||
icalendar = require 'icalendar'
|
||||
|
||||
# ---------- /v1 API ------------
|
||||
# Every url added beneath router is prefaced by /v1
|
||||
NO_TOKEN_OR_UID = err: "You must include a token and uid (user id) in your request"
|
||||
NO_USER_FOUND = err: "No user found."
|
||||
|
||||
# ---------- /api/v1 API ------------
|
||||
# Every url added beneath router is prefaced by /api/v1
|
||||
|
||||
###
|
||||
v1 API. Requires user-id and apiToken, task-id, direction. Test with:
|
||||
curl -X POST -H "Content-Type:application/json" -d '{"apiToken":"{TOKEN}"}' localhost:3000/v1/users/{UID}/tasks/productivity/up
|
||||
v1 API. Requires api-v1-user (user id) and api-v1-key (api key) headers, Test with:
|
||||
$ cd node_modules/racer && npm install && cd ../..
|
||||
$ mocha test/api.mocha.coffee
|
||||
###
|
||||
|
||||
router.post '/users/:uid/tasks/:taskId/:direction', (req, res) ->
|
||||
{uid, taskId, direction} = req.params
|
||||
{apiToken, title, service, icon} = req.body
|
||||
console.log {params:req.params, body:req.body} if process.env.NODE_ENV == 'development'
|
||||
router.get '/status', (req, res) ->
|
||||
res.json status: 'up'
|
||||
|
||||
# Send error responses for improper API call
|
||||
return res.send(500, 'request body "apiToken" required') unless apiToken
|
||||
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']
|
||||
auth = (req, res, next) ->
|
||||
uid = req.headers['x-api-user']
|
||||
token = req.headers['x-api-key']
|
||||
return res.json 401, NO_TOKEN_OR_UID unless uid || token
|
||||
|
||||
req._isServer = true
|
||||
model = req.getModel()
|
||||
model.fetch model.query('users').withIdAndToken(uid, apiToken), (err, result) ->
|
||||
return res.send(500, err) if err
|
||||
user = result
|
||||
userObj = user.get()
|
||||
if _.isEmpty(userObj)
|
||||
return res.send(500, "User with uid=#{uid}, token=#{apiToken} not found. Make sure you're not using your username, but your User Id")
|
||||
query = model.query('users').withIdAndToken(uid, token)
|
||||
|
||||
model.ref('_user', user)
|
||||
query.fetch (err, user) ->
|
||||
return res.json err: err if err
|
||||
req.user = user
|
||||
req.userObj = user.get()
|
||||
return res.json 401, NO_USER_FOUND if !req.userObj || _.isEmpty(req.userObj)
|
||||
req._isServer = true
|
||||
next()
|
||||
|
||||
# Create task if doesn't exist
|
||||
# TODO add service & icon to task
|
||||
unless model.get("_user.tasks.#{taskId}")
|
||||
model.refList "_habitList", "_user.tasks", "_user.habitIds"
|
||||
model.at('_habitList').push
|
||||
id: taskId
|
||||
type: 'habit'
|
||||
text: (title || taskId)
|
||||
value: 0
|
||||
up: true
|
||||
down: true
|
||||
notes: "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task."
|
||||
router.get '/user', auth, (req, res) ->
|
||||
user = req.userObj
|
||||
|
||||
score = scoring.Scoring(model)
|
||||
delta = score.score(taskId, direction)
|
||||
result = model.get ('_user.stats')
|
||||
result.delta = delta
|
||||
res.send(result)
|
||||
delete user.apiToken
|
||||
|
||||
res.json user
|
||||
|
||||
router.get '/user/task/:id', auth, (req, res) ->
|
||||
task = req.userObj.tasks[req.params.id]
|
||||
return res.json 400, err: "No task found." if !task || _.isEmpty(task)
|
||||
|
||||
res.json 200, task
|
||||
|
||||
validateTask = (req, res, next) ->
|
||||
task = {}
|
||||
newTask = { type, text, notes, value, up, down, completed } = req.body
|
||||
|
||||
# If we're updating, get the task from the user
|
||||
if req.method is 'PUT'
|
||||
task = req.userObj?.tasks[req.params.id]
|
||||
return res.json 400, err: "No task found." if !task || _.isEmpty(task)
|
||||
# Strip for now
|
||||
type = undefined
|
||||
delete newTask.type
|
||||
else if req.method is 'POST'
|
||||
unless /^(habit|todo|daily|reward)$/.test type
|
||||
return res.json 400, err: 'type must be habit, todo, daily, or reward'
|
||||
|
||||
text = sanitize(text).xss()
|
||||
notes = sanitize(notes).xss()
|
||||
value = sanitize(value).toInt()
|
||||
|
||||
switch type
|
||||
when 'habit'
|
||||
newTask.up = true unless typeof up is 'boolean'
|
||||
newTask.down = true unless typeof down is 'boolean'
|
||||
when 'daily', 'todo'
|
||||
newTask.completed = false unless typeof completed is 'boolean'
|
||||
|
||||
_.extend task, newTask
|
||||
req.task = task
|
||||
next()
|
||||
|
||||
router.put '/user/task/:id', auth, validateTask, (req, res) ->
|
||||
req.user.set "tasks.#{req.task.id}", req.task
|
||||
|
||||
res.json 200, req.task
|
||||
|
||||
router.post '/user/task', auth, validateTask, (req, res) ->
|
||||
task = req.task
|
||||
type = task.type
|
||||
|
||||
model = req.getModel()
|
||||
model.ref '_user', req.user
|
||||
model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
|
||||
model.at("_#{type}List").push task
|
||||
|
||||
res.json 201, task
|
||||
|
||||
router.get '/user/tasks', auth, (req, res) ->
|
||||
user = req.userObj
|
||||
return res.json 400, NO_USER_FOUND if !user || _.isEmpty(user)
|
||||
|
||||
model = req.getModel()
|
||||
model.ref '_user', req.user
|
||||
tasks = []
|
||||
types = ['habit','todo','daily','reward']
|
||||
if /^(habit|todo|daily|reward)$/.test req.query.type
|
||||
types = [req.query.type]
|
||||
for type in types
|
||||
model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
|
||||
tasks = tasks.concat model.get("_#{type}List")
|
||||
|
||||
res.json 200, tasks
|
||||
|
||||
router.get '/users/:uid/calendar.ics', (req, res) ->
|
||||
#return next() #disable for now
|
||||
|
|
@ -62,11 +122,11 @@ router.get '/users/:uid/calendar.ics', (req, res) ->
|
|||
model = req.getModel()
|
||||
query = model.query('users').withIdAndToken(uid, apiToken)
|
||||
query.fetch (err, result) ->
|
||||
return res.send(500, err) if err
|
||||
return res.send(400, err) if err
|
||||
tasks = result.get('tasks')
|
||||
# tasks = result[0].tasks
|
||||
tasksWithDates = _.filter tasks, (task) -> !!task.date
|
||||
return res.send(500, "No events found") if _.isEmpty(tasksWithDates)
|
||||
return res.send(400, "No events found") if _.isEmpty(tasksWithDates)
|
||||
|
||||
ical = new icalendar.iCalendar()
|
||||
ical.addProperty('NAME', 'HabitRPG')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
express = require 'express'
|
||||
router = new express.Router()
|
||||
|
||||
scoring = require '../app/scoring'
|
||||
_ = require 'underscore'
|
||||
icalendar = require('icalendar')
|
||||
|
||||
# ---------- Deprecated Paths ------------
|
||||
|
||||
deprecatedMessage = 'This API is no longer supported, see https://github.com/lefnire/habitrpg/wiki/API for new protocol'
|
||||
|
|
@ -9,4 +13,72 @@ router.get '/:uid/up/:score?', (req, res) -> res.send(500, deprecatedMessage)
|
|||
router.get '/:uid/down/:score?', (req, res) -> res.send(500, deprecatedMessage)
|
||||
router.post '/users/:uid/tasks/:taskId/:direction', (req, res) -> res.send(500, deprecatedMessage)
|
||||
|
||||
router.post '/v1/users/:uid/tasks/:taskId/:direction', (req, res) ->
|
||||
{uid, taskId, direction} = req.params
|
||||
{apiToken, 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 "apiToken" required') unless apiToken
|
||||
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 model.query('users').withIdAndToken(uid, apiToken), (err, result) ->
|
||||
return res.send(500, err) if err
|
||||
user = result
|
||||
userObj = user.get()
|
||||
if _.isEmpty(userObj)
|
||||
return res.send(500, "User with uid=#{uid}, token=#{apiToken} not found. Make sure you're not using your username, but your User Id")
|
||||
|
||||
model.ref('_user', user)
|
||||
req._isServer = true
|
||||
|
||||
# Create task if doesn't exist
|
||||
# TODO add service & icon to task
|
||||
unless model.get("_user.tasks.#{taskId}")
|
||||
model.refList "_habitList", "_user.tasks", "_user.habitIds"
|
||||
model.at('_habitList').push
|
||||
id: taskId
|
||||
type: 'habit'
|
||||
text: (title || taskId)
|
||||
value: 0
|
||||
up: true
|
||||
down: true
|
||||
notes: "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task."
|
||||
|
||||
score = new scoring.Scoring(model)
|
||||
delta = score.score(taskId, direction)
|
||||
result = model.get ('_user.stats')
|
||||
result.delta = delta
|
||||
res.send(result)
|
||||
|
||||
router.get '/v1/users/:uid/calendar.ics', (req, res) ->
|
||||
#return next() #disable for now
|
||||
{uid} = req.params
|
||||
{apiToken} = req.query
|
||||
|
||||
model = req.getModel()
|
||||
query = model.query('users').withIdAndToken(uid, apiToken)
|
||||
query.fetch (err, result) ->
|
||||
return res.send(500, err) if err
|
||||
tasks = result.get('tasks')
|
||||
# tasks = result[0].tasks
|
||||
tasksWithDates = _.filter tasks, (task) -> !!task.date
|
||||
return res.send(500, "No events found") if _.isEmpty(tasksWithDates)
|
||||
|
||||
ical = new icalendar.iCalendar()
|
||||
ical.addProperty('NAME', 'HabitRPG')
|
||||
_.each tasksWithDates, (task) ->
|
||||
event = new icalendar.VEvent(task.id);
|
||||
event.setSummary(task.text);
|
||||
d = new Date(task.date)
|
||||
d.date_only = true
|
||||
event.setDate d
|
||||
ical.addComponent event
|
||||
res.type('text/calendar')
|
||||
formattedIcal = ical.toString().replace(/DTSTART\:/g, 'DTSTART;VALUE=DATE:')
|
||||
res.send(200, formattedIcal)
|
||||
|
||||
module.exports = router
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ server = http.createServer expressApp
|
|||
module.exports = server
|
||||
|
||||
derby.use require('racer-db-mongo')
|
||||
store = derby.createStore
|
||||
module.exports.habitStore = store = derby.createStore
|
||||
db: {type: 'Mongo', uri: process.env.NODE_DB_URI, safe:true}
|
||||
listen: server
|
||||
|
||||
|
|
@ -74,6 +74,9 @@ mongo_store = new MongoStore {url: process.env.NODE_DB_URI}, ->
|
|||
)
|
||||
# Adds req.getModel method
|
||||
.use(store.modelMiddleware())
|
||||
# API should be hit before all other routes
|
||||
.use('/api/v1', require('./api').middleware)
|
||||
.use(require('./deprecated').middleware)
|
||||
# Show splash page for newcomers
|
||||
.use(middleware.splash)
|
||||
.use(priv.middleware)
|
||||
|
|
@ -81,9 +84,7 @@ mongo_store = new MongoStore {url: process.env.NODE_DB_URI}, ->
|
|||
.use(auth.middleware(strategies, options))
|
||||
# Creates an express middleware from the app's routes
|
||||
.use(app.router())
|
||||
.use('/v1', require('./api').middleware)
|
||||
.use(require('./static').middleware)
|
||||
.use(require('./deprecated').middleware)
|
||||
.use(expressApp.router)
|
||||
.use(serverError(root))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
module.exports.splash = (req, res, next) ->
|
||||
# This was an API call, not a page load
|
||||
return next() if req.is('json')
|
||||
|
||||
unless req.query?.play? or req.getModel().get('_userId')
|
||||
res.redirect('/splash.html')
|
||||
else
|
||||
next()
|
||||
|
||||
module.exports.view = (req, res, next) ->
|
||||
model = req.getModel()
|
||||
_view = model.get('_view') || {}
|
||||
## Set _mobileDevice to true or false so view can exclude portions from mobile device
|
||||
_view.mobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header 'User-Agent')
|
||||
_view.nodeEnv = process.env.NODE_ENV
|
||||
model.set '_view', _view
|
||||
next()
|
||||
model = req.getModel()
|
||||
_view = model.get('_view') || {}
|
||||
## Set _mobileDevice to true or false so view can exclude portions from mobile device
|
||||
_view.mobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header 'User-Agent')
|
||||
_view.nodeEnv = process.env.NODE_ENV
|
||||
model.set '_view', _view
|
||||
next()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ userAccess = (store) ->
|
|||
store.writeAccess "*", "users.*", -> # captures, value, accept, err ->
|
||||
accept = arguments[arguments.length-2]
|
||||
err = arguments[arguments.length - 1]
|
||||
# return err(derbyAuth.SESSION_INVALIDATED_ERROR) if derbyAuth.bustedSession(@)
|
||||
# return err(derbyAuth.SESSION_INVALIDATED_ERROR) if derbyAuth.bustedSession(@)
|
||||
|
||||
return accept(true) if derbyAuth.isServer(@)
|
||||
|
||||
return accept(false) if derbyAuth.bustedSession(@)
|
||||
|
||||
captures = arguments[0].split('.')
|
||||
|
|
@ -40,8 +43,7 @@ userAccess = (store) ->
|
|||
return accept(true)
|
||||
|
||||
# Same session (user.id = this.session.userId)
|
||||
if (uid is @session.userId) or derbyAuth.isServer(@)
|
||||
return accept(true)
|
||||
return accept(true) if uid is @session.userId
|
||||
|
||||
accept(false)
|
||||
|
||||
|
|
|
|||
245
test/api.mocha.coffee
Normal file
245
test/api.mocha.coffee
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
_ = require 'underscore'
|
||||
request = require 'superagent'
|
||||
expect = require 'expect.js'
|
||||
require 'coffee-script'
|
||||
|
||||
conf = require("nconf")
|
||||
conf.argv().env().file({file: __dirname + '../config.json'}).defaults
|
||||
|
||||
# Override normal ENV values with nconf ENV values (ENV values are used the same way without nconf)
|
||||
#FIXME can't get nconf file above to load...
|
||||
process.env.BASE_URL = conf.get("BASE_URL")
|
||||
process.env.FACEBOOK_KEY = conf.get("FACEBOOK_KEY")
|
||||
process.env.FACEBOOK_SECRET = conf.get("FACEBOOK_SECRET")
|
||||
process.env.NODE_DB_URI = 'mongodb://localhost/habirpg'
|
||||
|
||||
## monkey-patch expect.js for better diffs on mocha
|
||||
## see: https://github.com/LearnBoost/expect.js/pull/34
|
||||
|
||||
origBe = expect.Assertion::be
|
||||
expect.Assertion::be = expect.Assertion::equal = (obj) ->
|
||||
@_expected = obj
|
||||
origBe.call this, obj
|
||||
|
||||
# Custom modules
|
||||
character = require '../src/app/character'
|
||||
|
||||
###### Helpers & Variables ######
|
||||
|
||||
model = null
|
||||
uuid = null
|
||||
taskPath = null
|
||||
baseURL = 'http://localhost:1337/api/v1'
|
||||
|
||||
###### Specs ######
|
||||
|
||||
describe 'API', ->
|
||||
server = null
|
||||
store = null
|
||||
model = null
|
||||
user = null
|
||||
uid = null
|
||||
|
||||
before (done) ->
|
||||
server = require '../src/server'
|
||||
server.listen '1337', '0.0.0.0'
|
||||
server.on 'listening', (data) ->
|
||||
store = server.habitStore
|
||||
#store.flush()
|
||||
model = store.createModel()
|
||||
model.set '_userId', uid = model.id()
|
||||
user = character.newUserObject()
|
||||
user.apiToken = model.id()
|
||||
model.session = {userId:uid}
|
||||
model.set "users.#{uid}", user
|
||||
delete model.session
|
||||
# Crappy hack to let server start before tests run
|
||||
setTimeout done, 2000
|
||||
|
||||
describe 'Without token or user id', ->
|
||||
|
||||
it '/api/v1/status', (done) ->
|
||||
request.get("#{baseURL}/status")
|
||||
.set('Accept', 'application/json')
|
||||
.end (res) ->
|
||||
expect(res.statusCode).to.be 200
|
||||
expect(res.body.status).to.be 'up'
|
||||
done()
|
||||
|
||||
it '/api/v1/user', (done) ->
|
||||
request.get("#{baseURL}/user")
|
||||
.set('Accept', 'application/json')
|
||||
.end (res) ->
|
||||
expect(res.statusCode).to.be 401
|
||||
expect(res.body.err).to.be 'You must include a token and uid (user id) in your request'
|
||||
done()
|
||||
|
||||
describe 'With token and user id', ->
|
||||
params = null
|
||||
currentUser = null
|
||||
|
||||
before ->
|
||||
user = model.at("users.#{uid}")
|
||||
currentUser = user.get()
|
||||
params =
|
||||
title: 'Title'
|
||||
text: 'Text'
|
||||
type: 'habit'
|
||||
|
||||
beforeEach ->
|
||||
currentUser = user.get()
|
||||
|
||||
it 'GET /api/v1/user', (done) ->
|
||||
request.get("#{baseURL}/user")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
expect(res.body.id).not.to.be.empty()
|
||||
self = _.clone(currentUser)
|
||||
delete self.apiToken
|
||||
|
||||
expect(res.body).to.eql self
|
||||
done()
|
||||
|
||||
it 'GET /api/v1/user/task/:id', (done) ->
|
||||
tid = _.pluck(currentUser.tasks, 'id')[0]
|
||||
request.get("#{baseURL}/user/task/#{tid}")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
expect(res.body).to.eql currentUser.tasks[tid]
|
||||
done()
|
||||
|
||||
it 'POST /api/v1/user/task', (done) ->
|
||||
request.post("#{baseURL}/user/task")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send(params)
|
||||
.end (res) ->
|
||||
query = model.query('users').withIdAndToken(currentUser.id, currentUser.apiToken)
|
||||
query.fetch (err, user) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 201
|
||||
expect(res.body.id).not.to.be.empty()
|
||||
# Ensure that user owns the newly created object
|
||||
expect(user.get().tasks[res.body.id]).to.be.an('object')
|
||||
done()
|
||||
|
||||
it 'POST /api/v1/user/task (without type)', (done) ->
|
||||
request.post("#{baseURL}/user/task")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send({})
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be 'type must be habit, todo, daily, or reward'
|
||||
expect(res.statusCode).to.be 400
|
||||
done()
|
||||
|
||||
it 'POST /api/v1/user/task (only type)', (done) ->
|
||||
request.post("#{baseURL}/user/task")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send(type: 'habit')
|
||||
.end (res) ->
|
||||
query = model.query('users').withIdAndToken(currentUser.id, currentUser.apiToken)
|
||||
query.fetch (err, user) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 201
|
||||
expect(res.body.id).not.to.be.empty()
|
||||
# Ensure that user owns the newly created object
|
||||
expect(user.get().tasks[res.body.id]).to.be.an('object')
|
||||
done()
|
||||
|
||||
it 'PUT /api/v1/user/task/:id', (done) ->
|
||||
tid = _.pluck(currentUser.tasks, 'id')[0]
|
||||
request.put("#{baseURL}/user/task/#{tid}")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send(text: 'bye')
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
currentUser.tasks[tid].text = 'bye'
|
||||
expect(res.body).to.eql currentUser.tasks[tid]
|
||||
done()
|
||||
|
||||
it 'PUT /api/v1/user/task/:id (shouldnt update type)', (done) ->
|
||||
tid = _.pluck(currentUser.tasks, 'id')[1]
|
||||
type = if currentUser.tasks[tid].type is 'habit' then 'daily' else 'habit'
|
||||
request.put("#{baseURL}/user/task/#{tid}")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send(type: type, text: 'fishman')
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
currentUser.tasks[tid].text = 'fishman'
|
||||
expect(res.body).to.eql currentUser.tasks[tid]
|
||||
done()
|
||||
|
||||
it 'PUT /api/v1/user/task/:id (update notes)', (done) ->
|
||||
tid = _.pluck(currentUser.tasks, 'id')[2]
|
||||
request.put("#{baseURL}/user/task/#{tid}")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send(text: 'hi',notes:'foobar matey')
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
currentUser.tasks[tid].text = 'hi'
|
||||
currentUser.tasks[tid].notes = 'foobar matey'
|
||||
expect(res.body).to.eql currentUser.tasks[tid]
|
||||
done()
|
||||
|
||||
it 'GET /api/v1/user/tasks', (done) ->
|
||||
request.get("#{baseURL}/user/tasks")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.end (res) ->
|
||||
query = model.query('users').withIdAndToken(currentUser.id, currentUser.apiToken)
|
||||
query.fetch (err, user) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
model.ref '_user', user
|
||||
tasks = []
|
||||
for type in ['habit','todo','daily','reward']
|
||||
model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
|
||||
tasks = tasks.concat model.get("_#{type}List")
|
||||
# Ensure that user owns the tasks
|
||||
expect(res.body.length).to.equal tasks.length
|
||||
# Ensure that the two sets are equal
|
||||
expect(_.difference(_.pluck(res.body,'id'), _.pluck(tasks,'id')).length).to.equal 0
|
||||
done()
|
||||
|
||||
it 'GET /api/v1/user/tasks (todos)', (done) ->
|
||||
request.get("#{baseURL}/user/tasks")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.query(type:'todo')
|
||||
.end (res) ->
|
||||
query = model.query('users').withIdAndToken(currentUser.id, currentUser.apiToken)
|
||||
query.fetch (err, user) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
model.ref '_user', user
|
||||
model.refList "_todoList", "_user.tasks", "_user.todoIds"
|
||||
tasks = model.get("_todoList")
|
||||
# Ensure that user owns the tasks
|
||||
expect(res.body.length).to.equal tasks.length
|
||||
# Ensure that the two sets are equal
|
||||
expect(_.difference(_.pluck(res.body,'id'), _.pluck(tasks,'id')).length).to.equal 0
|
||||
done()
|
||||
|
|
@ -12,8 +12,8 @@ casper.start "#{url}/?play=1", ->
|
|||
@fill 'form#derby-auth-register',
|
||||
username: user1.id
|
||||
email: "{user1.id}@gmail.com"
|
||||
'email-confirmation': "{user1.id}@gmail.com"
|
||||
password: 'habitrpg123'
|
||||
'password-confirmation': "habitrpg123"
|
||||
, true
|
||||
casper.thenOpen "#{url}/logout"
|
||||
casper.thenOpen "#{url}/?play=1", ->
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
--colors
|
||||
--reporter spec
|
||||
--timeout 1200
|
||||
--timeout 2800
|
||||
--ignore-leaks
|
||||
--growl
|
||||
--debug
|
||||
--compilers coffee:coffee-script
|
||||
|
|
|
|||
Loading…
Reference in a new issue