mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Made the server side of the patch system.
This commit is contained in:
parent
ff73aecf08
commit
2f988ba485
22 changed files with 317 additions and 25 deletions
|
@ -1,12 +1,11 @@
|
|||
mongoose = require('mongoose')
|
||||
plugins = require('../plugins/plugins')
|
||||
|
||||
ArticleSchema = new mongoose.Schema(
|
||||
body: String,
|
||||
)
|
||||
ArticleSchema = new mongoose.Schema(body: String, {strict:false})
|
||||
|
||||
ArticleSchema.plugin(plugins.NamedPlugin)
|
||||
ArticleSchema.plugin(plugins.VersionedPlugin)
|
||||
ArticleSchema.plugin(plugins.SearchablePlugin, {searchable: ['body', 'name']})
|
||||
ArticleSchema.plugin(plugins.PatchablePlugin)
|
||||
|
||||
module.exports = mongoose.model('article', ArticleSchema)
|
||||
|
|
|
@ -9,4 +9,8 @@ ArticleHandler = class ArticleHandler extends Handler
|
|||
hasAccess: (req) ->
|
||||
req.method is 'GET' or req.user?.isAdmin()
|
||||
|
||||
hasAccessToDocument: (req, document, method=null) ->
|
||||
return true if req.method is 'GET' or method is 'get' or req.user?.isAdmin()
|
||||
return false
|
||||
|
||||
module.exports = new ArticleHandler()
|
||||
|
|
|
@ -6,8 +6,9 @@ c.extendNamedProperties ArticleSchema # name first
|
|||
ArticleSchema.properties.body = { type: 'string', title: 'Content', format: 'markdown' }
|
||||
ArticleSchema.properties.i18n = { type: 'object', title: 'i18n', format: 'i18n', props: ['body'] }
|
||||
|
||||
c.extendBasicProperties(ArticleSchema, 'article')
|
||||
c.extendSearchableProperties(ArticleSchema)
|
||||
c.extendVersionedProperties(ArticleSchema, 'article')
|
||||
c.extendBasicProperties ArticleSchema, 'article'
|
||||
c.extendSearchableProperties ArticleSchema
|
||||
c.extendVersionedProperties ArticleSchema, 'article'
|
||||
c.extendPatchableProperties ArticleSchema
|
||||
|
||||
module.exports = ArticleSchema
|
||||
|
|
|
@ -3,6 +3,7 @@ mongoose = require('mongoose')
|
|||
Grid = require 'gridfs-stream'
|
||||
errors = require './errors'
|
||||
log = require 'winston'
|
||||
Patch = require '../patches/Patch'
|
||||
|
||||
PROJECT = {original:1, name:1, version:1, description: 1, slug:1, kind: 1}
|
||||
FETCH_LIMIT = 200
|
||||
|
@ -27,8 +28,7 @@ module.exports = class Handler
|
|||
getEditableProperties: (req, document) ->
|
||||
props = @editableProperties.slice()
|
||||
isBrandNew = req.method is 'POST' and not req.body.original
|
||||
if isBrandNew
|
||||
props = props.concat @postEditableProperties
|
||||
props = props.concat @postEditableProperties if isBrandNew
|
||||
|
||||
if @modelClass.schema.uses_coco_permissions
|
||||
# can only edit permissions if this is a brand new property,
|
||||
|
@ -37,8 +37,8 @@ module.exports = class Handler
|
|||
if isBrandNew or isOwner or req.user?.isAdmin()
|
||||
props.push 'permissions'
|
||||
|
||||
if @modelClass.schema.uses_coco_versions
|
||||
props.push 'commitMessage'
|
||||
props.push 'commitMessage' if @modelClass.schema.uses_coco_versions
|
||||
props.push 'allowPatches' if @modelClass.schema.is_patchable
|
||||
|
||||
props
|
||||
|
||||
|
@ -93,8 +93,32 @@ module.exports = class Handler
|
|||
|
||||
getByRelationship: (req, res, args...) ->
|
||||
# this handler should be overwritten by subclasses
|
||||
if @modelClass.schema.is_patchable
|
||||
return @getPatchesFor(req, res, args[0]) if req.route.method is 'get' and args[1] is 'patches'
|
||||
return @setListening(req, res, args[0]) if req.route.method is 'put' and args[1] is 'listen'
|
||||
return @sendNotFoundError(res)
|
||||
|
||||
getPatchesFor: (req, res, id) ->
|
||||
query = { 'target.original': mongoose.Types.ObjectId(id), status: req.query.status or 'pending' }
|
||||
Patch.find(query).sort('-created').exec (err, patches) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
patches = (patch.toObject() for patch in patches)
|
||||
@sendSuccess(res, patches)
|
||||
|
||||
setListening: (req, res, id) ->
|
||||
@getDocumentForIdOrSlug id, (err, document) =>
|
||||
return @sendUnauthorizedError(res) unless @hasAccessToDocument(req, document, 'get')
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless document?
|
||||
listeners = document.get('listeners') or []
|
||||
me = req.user.get('_id')
|
||||
listeners = (l for l in listeners when not l.equals(me))
|
||||
listeners.push me if req.body.on
|
||||
document.set 'listeners', listeners
|
||||
document.save (err, document) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, @formatEntity(req, document))
|
||||
|
||||
search: (req, res) ->
|
||||
unless @modelClass.schema.uses_coco_search
|
||||
return @sendNotFoundError(res)
|
||||
|
@ -224,6 +248,7 @@ module.exports = class Handler
|
|||
document.set('original', document._id)
|
||||
document.set('creator', req.user._id)
|
||||
@saveChangesToDocument req, document, (err) =>
|
||||
console.log 'saved new version', document.toObject()
|
||||
return @sendBadInputError(res, err.errors) if err?.valid is false
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, @formatEntity(req, document))
|
||||
|
|
|
@ -59,6 +59,9 @@ patchableProps = ->
|
|||
_id: me.objectId(links: [{rel: "db", href: "/db/patch/{($)}"}], title: "Patch ID", description: "A reference to the patch.")
|
||||
status: { enum: ['pending', 'accepted', 'rejected', 'cancelled']}
|
||||
})
|
||||
allowPatches: { type: 'boolean' }
|
||||
listeners: me.array({title:'Listeners'},
|
||||
me.objectId(links: [{rel: 'extra', href: "/db/user/{($)}"}]))
|
||||
|
||||
me.extendPatchableProperties = (schema) ->
|
||||
schema.properties = {} unless schema.properties?
|
||||
|
|
|
@ -10,6 +10,7 @@ LevelSchema.plugin(plugins.NamedPlugin)
|
|||
LevelSchema.plugin(plugins.PermissionsPlugin)
|
||||
LevelSchema.plugin(plugins.VersionedPlugin)
|
||||
LevelSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
||||
LevelSchema.plugin(plugins.PatchablePlugin)
|
||||
|
||||
LevelSchema.pre 'init', (next) ->
|
||||
return next() unless jsonschema.properties?
|
||||
|
|
|
@ -7,10 +7,11 @@ LevelComponentSchema = new mongoose.Schema {
|
|||
system: String
|
||||
}, {strict: false}
|
||||
|
||||
LevelComponentSchema.plugin(plugins.NamedPlugin)
|
||||
LevelComponentSchema.plugin(plugins.PermissionsPlugin)
|
||||
LevelComponentSchema.plugin(plugins.VersionedPlugin)
|
||||
LevelComponentSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description', 'system']})
|
||||
LevelComponentSchema.plugin plugins.NamedPlugin
|
||||
LevelComponentSchema.plugin plugins.PermissionsPlugin
|
||||
LevelComponentSchema.plugin plugins.VersionedPlugin
|
||||
LevelComponentSchema.plugin plugins.SearchablePlugin, {searchable: ['name', 'description', 'system']}
|
||||
LevelComponentSchema.plugin plugins.PatchablePlugin
|
||||
|
||||
LevelComponentSchema.pre 'init', (next) ->
|
||||
return next() unless jsonschema.properties?
|
||||
|
|
|
@ -115,5 +115,6 @@ c.extendBasicProperties LevelComponentSchema, 'level.component'
|
|||
c.extendSearchableProperties LevelComponentSchema
|
||||
c.extendVersionedProperties LevelComponentSchema, 'level.component'
|
||||
c.extendPermissionsProperties LevelComponentSchema, 'level.component'
|
||||
c.extendPatchableProperties LevelComponentSchema
|
||||
|
||||
module.exports = LevelComponentSchema
|
||||
|
|
|
@ -38,8 +38,7 @@ LevelHandler = class LevelHandler extends Handler
|
|||
return @getLeaderboardFacebookFriends(req, res, args[0]) if args[1] is 'leaderboard_facebook_friends'
|
||||
return @getLeaderboardGPlusFriends(req, res, args[0]) if args[1] is 'leaderboard_gplus_friends'
|
||||
return @getHistogramData(req, res, args[0]) if args[1] is 'histogram_data'
|
||||
|
||||
return @sendNotFoundError(res)
|
||||
super(arguments...)
|
||||
|
||||
fetchLevelByIDAndHandleErrors: (id, req, res, callback) ->
|
||||
@getDocumentForIdOrSlug id, (err, level) =>
|
||||
|
|
|
@ -243,6 +243,7 @@ c.extendBasicProperties LevelSchema, 'level'
|
|||
c.extendSearchableProperties LevelSchema
|
||||
c.extendVersionedProperties LevelSchema, 'level'
|
||||
c.extendPermissionsProperties LevelSchema, 'level'
|
||||
c.extendPatchableProperties LevelSchema
|
||||
|
||||
module.exports = LevelSchema
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class LevelSessionHandler extends Handler
|
|||
|
||||
getByRelationship: (req, res, args...) ->
|
||||
return @getActiveSessions req, res if args.length is 2 and args[1] is 'active'
|
||||
return @sendNotFoundError(res)
|
||||
super(arguments...)
|
||||
|
||||
getActiveSessions: (req, res) ->
|
||||
return @sendUnauthorizedError(res) unless req.user.isAdmin()
|
||||
|
|
|
@ -10,6 +10,7 @@ LevelSystemSchema.plugin(plugins.NamedPlugin)
|
|||
LevelSystemSchema.plugin(plugins.PermissionsPlugin)
|
||||
LevelSystemSchema.plugin(plugins.VersionedPlugin)
|
||||
LevelSystemSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
||||
LevelSystemSchema.plugin(plugins.PatchablePlugin)
|
||||
|
||||
LevelSystemSchema.pre 'init', (next) ->
|
||||
return next() unless jsonschema.properties?
|
||||
|
|
|
@ -101,6 +101,7 @@ _.extend LevelSystemSchema.properties,
|
|||
c.extendBasicProperties LevelSystemSchema, 'level.system'
|
||||
c.extendSearchableProperties LevelSystemSchema
|
||||
c.extendVersionedProperties LevelSystemSchema, 'level.system'
|
||||
c.extendPermissionsProperties LevelSystemSchema, 'level.system'
|
||||
c.extendPermissionsProperties LevelSystemSchema
|
||||
c.extendPatchableProperties LevelSystemSchema
|
||||
|
||||
module.exports = LevelSystemSchema
|
||||
|
|
|
@ -5,8 +5,9 @@ ThangTypeSchema = new mongoose.Schema({
|
|||
body: String,
|
||||
}, {strict: false})
|
||||
|
||||
ThangTypeSchema.plugin(plugins.NamedPlugin)
|
||||
ThangTypeSchema.plugin(plugins.VersionedPlugin)
|
||||
ThangTypeSchema.plugin(plugins.SearchablePlugin, {searchable: ['name']})
|
||||
ThangTypeSchema.plugin plugins.NamedPlugin
|
||||
ThangTypeSchema.plugin plugins.VersionedPlugin
|
||||
ThangTypeSchema.plugin plugins.SearchablePlugin, {searchable: ['name']}
|
||||
ThangTypeSchema.plugin plugins.PatchablePlugin
|
||||
|
||||
module.exports = mongoose.model('thang.type', ThangTypeSchema)
|
||||
|
|
|
@ -146,8 +146,9 @@ ThangTypeSchema.definitions =
|
|||
action: ActionSchema
|
||||
sound: SoundSchema
|
||||
|
||||
c.extendBasicProperties(ThangTypeSchema, 'thang.type')
|
||||
c.extendSearchableProperties(ThangTypeSchema)
|
||||
c.extendVersionedProperties(ThangTypeSchema, 'thang.type')
|
||||
c.extendBasicProperties ThangTypeSchema, 'thang.type'
|
||||
c.extendSearchableProperties ThangTypeSchema
|
||||
c.extendVersionedProperties ThangTypeSchema, 'thang.type'
|
||||
c.extendPatchableProperties ThangTypeSchema
|
||||
|
||||
module.exports = ThangTypeSchema
|
||||
|
|
47
server/patches/Patch.coffee
Normal file
47
server/patches/Patch.coffee
Normal file
|
@ -0,0 +1,47 @@
|
|||
mongoose = require('mongoose')
|
||||
{handlers} = require '../commons/mapping'
|
||||
|
||||
PatchSchema = new mongoose.Schema({}, {strict: false})
|
||||
|
||||
PatchSchema.pre 'save', (next) ->
|
||||
return next() unless @isNew # patch can't be altered after creation, so only need to check data once
|
||||
target = @get('target')
|
||||
targetID = target.id
|
||||
Handler = require '../commons/Handler'
|
||||
if not Handler.isID(targetID)
|
||||
err = new Error('Invalid input.')
|
||||
err.response = {message:"isn't a MongoDB id.", property:'target.id'}
|
||||
err.code = 422
|
||||
return next(err)
|
||||
|
||||
collection = target.collection
|
||||
handler = require('../' + handlers[collection])
|
||||
handler.getDocumentForIdOrSlug targetID, (err, document) =>
|
||||
if err
|
||||
err = new Error('Server error.')
|
||||
err.response = {message:'', property:'target.id'}
|
||||
err.code = 500
|
||||
return next(err)
|
||||
|
||||
if not document
|
||||
err = new Error('Target of patch not found.')
|
||||
err.response = {message:'was not found.', property:'target.id'}
|
||||
err.code = 404
|
||||
return next(err)
|
||||
|
||||
target.id = document.get('_id')
|
||||
if handler.modelClass.schema.uses_coco_versions
|
||||
target.original = document.get('original')
|
||||
version = document.get('version')
|
||||
target.version = _.pick document.get('version'), 'major', 'minor'
|
||||
@set('target', target)
|
||||
else
|
||||
target.original = targetID
|
||||
|
||||
patches = document.get('patches') or []
|
||||
patches.push @_id
|
||||
console.log 'PATCH PUSHED', @_id
|
||||
document.set 'patches', patches
|
||||
document.save (err) -> next(err)
|
||||
|
||||
module.exports = mongoose.model('patch', PatchSchema)
|
55
server/patches/patch_handler.coffee
Normal file
55
server/patches/patch_handler.coffee
Normal file
|
@ -0,0 +1,55 @@
|
|||
Patch = require('./Patch')
|
||||
Handler = require('../commons/Handler')
|
||||
schema = require './patch_schema'
|
||||
{handlers} = require '../commons/mapping'
|
||||
mongoose = require('mongoose')
|
||||
|
||||
PatchHandler = class PatchHandler extends Handler
|
||||
modelClass: Patch
|
||||
editableProperties: []
|
||||
postEditableProperties: ['delta', 'target']
|
||||
jsonSchema: require './patch_schema'
|
||||
|
||||
makeNewInstance: (req) ->
|
||||
patch = super(req)
|
||||
patch.set 'creator', req.user._id
|
||||
patch.set 'created', new Date().toISOString()
|
||||
patch.set 'status', 'pending'
|
||||
patch
|
||||
|
||||
getByRelationship: (req, res, args...) ->
|
||||
return @setStatus(req, res, args[0]) if req.route.method is 'put' and args[1] is 'status'
|
||||
super(arguments...)
|
||||
|
||||
setStatus: (req, res, id) ->
|
||||
newStatus = req.body.status
|
||||
unless newStatus in ['rejected', 'accepted', 'withdrawn']
|
||||
return @sendBadInputError(res, "Status must be 'rejected', 'accepted', or 'withdrawn'")
|
||||
|
||||
@getDocumentForIdOrSlug id, (err, patch) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless patch?
|
||||
targetInfo = patch.get('target')
|
||||
targetHandler = require('../' + handlers[targetInfo.collection])
|
||||
targetModel = targetHandler.modelClass
|
||||
|
||||
query = { 'original': targetInfo.original }
|
||||
sort = { 'version.major': -1, 'version.minor': -1 }
|
||||
targetModel.findOne(query).sort(sort).exec (err, target) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless target?
|
||||
return @sendUnauthorizedError(res) unless targetHandler.hasAccessToDocument(req, target, 'get')
|
||||
|
||||
if newStatus in ['rejected', 'accepted']
|
||||
return @sendUnauthorizedError(res) unless targetHandler.hasAccessToDocument(req, target, 'put')
|
||||
|
||||
if newStatus is 'withdrawn'
|
||||
return @sendUnauthorizedError(res) unless req.user.get('_id').equals patch.get('creator')
|
||||
|
||||
# these require callbacks
|
||||
patch.update {$set:{status:newStatus}}, {}, ->
|
||||
target.update {$pull:{patches:patch.get('_id')}}, {}, ->
|
||||
@sendSuccess(res, null)
|
||||
|
||||
|
||||
module.exports = new PatchHandler()
|
28
server/patches/patch_schema.coffee
Normal file
28
server/patches/patch_schema.coffee
Normal file
|
@ -0,0 +1,28 @@
|
|||
c = require '../commons/schemas'
|
||||
|
||||
patchables = ['level', 'thang_type', 'level_system', 'level_component', 'article']
|
||||
|
||||
PatchSchema = c.object({title:'Patch', required:['target', 'delta']}, {
|
||||
delta: { title: 'Delta', type:['array', 'object'] }
|
||||
title: c.shortString()
|
||||
description: c.shortString({maxLength: 500})
|
||||
creator: c.objectId(links: [{rel: 'extra', href: "/db/user/{($)}"}])
|
||||
created: c.date( { title: 'Created', readOnly: true })
|
||||
status: { enum: ['pending', 'accepted', 'rejected', 'withdrawn']}
|
||||
|
||||
target: c.object({title: 'Target', required:['collection', 'id']}, {
|
||||
collection: { enum: patchables }
|
||||
id: c.objectId(title: 'Target ID') # search by this if not versioned
|
||||
|
||||
# if target is versioned, want to know that info too
|
||||
original: c.objectId(title: 'Target Original') # search by this if versioned
|
||||
version:
|
||||
properties:
|
||||
major: { type: 'number', minimum: 0 }
|
||||
minor: { type: 'number', minimum: 0 }
|
||||
})
|
||||
})
|
||||
|
||||
c.extendBasicProperties(PatchSchema, 'patch')
|
||||
|
||||
module.exports = PatchSchema
|
|
@ -2,6 +2,10 @@ mongoose = require('mongoose')
|
|||
User = require('../users/User')
|
||||
textSearch = require('mongoose-text-search')
|
||||
|
||||
module.exports.PatchablePlugin = (schema) ->
|
||||
schema.is_patchable = true
|
||||
schema.index({'target.original':1, 'status':'1', 'created':-1})
|
||||
|
||||
module.exports.NamedPlugin = (schema) ->
|
||||
schema.add({name: String, slug: String})
|
||||
schema.index({'slug': 1}, {unique: true, sparse: true, name: 'slug index'})
|
||||
|
|
|
@ -171,7 +171,7 @@ UserHandler = class UserHandler extends Handler
|
|||
return @getNamesByIds(req, res) if args[1] is 'names'
|
||||
return @nameToID(req, res, args[0]) if args[1] is 'nameToID'
|
||||
return @getLevelSessions(req, res, args[0]) if args[1] is 'level.sessions'
|
||||
return @sendNotFoundError(res)
|
||||
super(arguments...)
|
||||
|
||||
agreeToCLA: (req, res) ->
|
||||
return @sendUnauthorizedError(res) unless req.user
|
||||
|
|
|
@ -10,6 +10,7 @@ _.mixin(_.str.exports())
|
|||
GLOBAL.mongoose = require 'mongoose'
|
||||
mongoose.connect('mongodb://localhost/coco_unittest')
|
||||
path = require('path')
|
||||
GLOBAL.testing = true
|
||||
|
||||
models_path = [
|
||||
'../../server/articles/Article'
|
||||
|
@ -19,6 +20,7 @@ models_path = [
|
|||
'../../server/levels/sessions/LevelSession'
|
||||
'../../server/levels/thangs/LevelThangType'
|
||||
'../../server/users/User'
|
||||
'../../server/patches/Patch'
|
||||
]
|
||||
|
||||
for m in models_path
|
||||
|
|
117
test/server/functional/patch.spec.coffee
Normal file
117
test/server/functional/patch.spec.coffee
Normal file
|
@ -0,0 +1,117 @@
|
|||
require '../common'
|
||||
|
||||
describe '/db/patch', ->
|
||||
request = require 'request'
|
||||
it 'clears the db first', (done) ->
|
||||
clearModels [User, Article, Patch], (err) ->
|
||||
throw err if err
|
||||
done()
|
||||
|
||||
article = {name: 'Yo', body:'yo ma'}
|
||||
articleURL = getURL('/db/article')
|
||||
articles = {}
|
||||
|
||||
patchURL = getURL('/db/patch')
|
||||
patches = {}
|
||||
patch =
|
||||
delta: {name:['test']}
|
||||
target:
|
||||
id:null
|
||||
collection: 'article'
|
||||
|
||||
it 'creates an Article to patch', (done) ->
|
||||
loginAdmin ->
|
||||
request.post {uri:articleURL, json:patch}, (err, res, body) ->
|
||||
articles[0] = body
|
||||
patch.target.id = articles[0]._id
|
||||
done()
|
||||
|
||||
it "allows someone to submit a patch to something they don't control", (done) ->
|
||||
loginJoe (joe) ->
|
||||
request.post {uri: patchURL, json: patch}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(body.target.original).toBeDefined()
|
||||
expect(body.target.version.major).toBeDefined()
|
||||
expect(body.target.version.minor).toBeDefined()
|
||||
expect(body.status).toBe('pending')
|
||||
expect(body.created).toBeDefined()
|
||||
expect(body.creator).toBe(joe.id)
|
||||
patches[0] = body
|
||||
done()
|
||||
|
||||
it 'adds a patch to the target document', (done) ->
|
||||
Article.findOne({}).exec (err, article) ->
|
||||
expect(article.toObject().patches[0]).toBeDefined()
|
||||
done()
|
||||
|
||||
it 'shows up in patch requests', (done) ->
|
||||
patchesURL = getURL("/db/article/#{articles[0]._id}/patches")
|
||||
request.get {uri: patchesURL}, (err, res, body) ->
|
||||
body = JSON.parse(body)
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(body.length).toBe(1)
|
||||
done()
|
||||
|
||||
it 'allows you to set yourself as listening', (done) ->
|
||||
listeningURL = getURL("/db/article/#{articles[0]._id}/listen")
|
||||
request.put {uri: listeningURL, json: {on:true}}, (err, res, body) ->
|
||||
expect(body.listeners[0]).toBeDefined()
|
||||
done()
|
||||
|
||||
it 'added the listener to the target document', (done) ->
|
||||
Article.findOne({}).exec (err, article) ->
|
||||
expect(article.toObject().listeners[0]).toBeDefined()
|
||||
done()
|
||||
|
||||
it 'does not add duplicate listeners', (done) ->
|
||||
listeningURL = getURL("/db/article/#{articles[0]._id}/listen")
|
||||
request.put {uri: listeningURL, json: {on:true}}, (err, res, body) ->
|
||||
expect(body.listeners.length).toBe(1)
|
||||
done()
|
||||
|
||||
it 'allows removing yourself', (done) ->
|
||||
listeningURL = getURL("/db/article/#{articles[0]._id}/listen")
|
||||
request.put {uri: listeningURL, json: {on:false}}, (err, res, body) ->
|
||||
expect(body.listeners.length).toBe(0)
|
||||
done()
|
||||
|
||||
it 'allows the submitter to withdraw the pull request', (done) ->
|
||||
statusURL = getURL("/db/patch/#{patches[0]._id}/status")
|
||||
request.put {uri: statusURL, json: {status:'withdrawn'}}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(200)
|
||||
Patch.findOne({}).exec (err, article) ->
|
||||
expect(article.get('status')).toBe 'withdrawn'
|
||||
Article.findOne({}).exec (err, article) ->
|
||||
expect(article.toObject().patches.length).toBe(0)
|
||||
done()
|
||||
|
||||
it 'does not allow the submitter to reject or accept the pull request', (done) ->
|
||||
statusURL = getURL("/db/patch/#{patches[0]._id}/status")
|
||||
request.put {uri: statusURL, json: {status:'rejected'}}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(403)
|
||||
request.put {uri: statusURL, json: {status:'accepted'}}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(403)
|
||||
Patch.findOne({}).exec (err, article) ->
|
||||
expect(article.get('status')).toBe 'withdrawn'
|
||||
done()
|
||||
|
||||
it 'allows the recipient to accept or reject the pull request', (done) ->
|
||||
statusURL = getURL("/db/patch/#{patches[0]._id}/status")
|
||||
loginAdmin ->
|
||||
request.put {uri: statusURL, json: {status:'rejected'}}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(200)
|
||||
Patch.findOne({}).exec (err, article) ->
|
||||
expect(article.get('status')).toBe 'rejected'
|
||||
request.put {uri: statusURL, json: {status:'accepted'}}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(200)
|
||||
Patch.findOne({}).exec (err, article) ->
|
||||
expect(article.get('status')).toBe 'accepted'
|
||||
done()
|
||||
|
||||
it 'does not allow the recipient to withdraw the pull request', (done) ->
|
||||
statusURL = getURL("/db/patch/#{patches[0]._id}/status")
|
||||
request.put {uri: statusURL, json: {status:'withdrawn'}}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(403)
|
||||
Patch.findOne({}).exec (err, article) ->
|
||||
expect(article.get('status')).toBe 'accepted'
|
||||
done()
|
Loading…
Reference in a new issue