2014-04-08 22:26:19 -04:00
|
|
|
require '../common'
|
2016-04-06 13:56:06 -04:00
|
|
|
User = require '../../../server/models/User'
|
|
|
|
Article = require '../../../server/models/Article'
|
|
|
|
Patch = require '../../../server/models/Patch'
|
|
|
|
request = require '../request'
|
2016-08-18 16:29:52 -04:00
|
|
|
utils = require '../utils'
|
2016-09-07 19:15:54 -04:00
|
|
|
co = require 'co'
|
|
|
|
Promise = require 'bluebird'
|
|
|
|
|
|
|
|
makeArticle = utils.wrap (done) ->
|
|
|
|
@creator = yield utils.initAdmin()
|
|
|
|
yield utils.loginUser(@creator)
|
|
|
|
@article = yield utils.makeArticle()
|
|
|
|
@json = {
|
2014-04-10 16:09:44 -04:00
|
|
|
commitMessage: 'Accept this patch!'
|
2016-09-07 19:15:54 -04:00
|
|
|
delta: { name: ['test'] }
|
2014-04-08 22:26:19 -04:00
|
|
|
target:
|
2016-09-07 19:15:54 -04:00
|
|
|
id: @article.id
|
2014-04-08 22:26:19 -04:00
|
|
|
collection: 'article'
|
2016-09-07 19:15:54 -04:00
|
|
|
}
|
|
|
|
@url = utils.getURL('/db/patch')
|
|
|
|
@user = yield utils.initUser()
|
|
|
|
yield utils.loginUser(@user)
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe 'POST /db/patch', ->
|
|
|
|
beforeEach utils.wrap (done) ->
|
|
|
|
yield utils.clearModels([User, Patch, Article])
|
|
|
|
done()
|
|
|
|
|
|
|
|
beforeEach makeArticle
|
|
|
|
|
|
|
|
it 'allows someone to submit a patch to something they don\'t control', utils.wrap (done) ->
|
|
|
|
[res, body] = yield request.postAsync { @url, @json }
|
|
|
|
expect(res.statusCode).toBe(201)
|
|
|
|
expect(body.target.original).toBe(@article.get('original').toString())
|
|
|
|
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(@user.id)
|
|
|
|
done()
|
2014-04-08 22:26:19 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'adds a patch to the target document', utils.wrap (done) ->
|
|
|
|
[res, body] = yield request.postAsync { @url, @json }
|
|
|
|
article = yield Article.findById(@article.id)
|
|
|
|
expect(article.get('patches').length).toBe(1)
|
|
|
|
done()
|
2014-04-08 22:26:19 -04:00
|
|
|
|
2016-09-16 16:19:39 -04:00
|
|
|
it 'is always based on the latest document', utils.wrap (done) ->
|
|
|
|
@json.delta = {i18n: [{de: {name:'German translation'}}]}
|
|
|
|
[res, body] = yield request.postAsync { @url, @json }
|
|
|
|
expect(res.statusCode).toBe(201)
|
|
|
|
expect(res.body.status).toBe('accepted')
|
|
|
|
[res, body] = yield request.postAsync { @url, @json }
|
|
|
|
expect(res.statusCode).toBe(422) # should be a no-change
|
|
|
|
done()
|
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'shows up in patch requests', utils.wrap (done) ->
|
|
|
|
[res, body] = yield request.postAsync { @url, @json }
|
|
|
|
patchID = res.body._id
|
|
|
|
url = utils.getURL("/db/article/#{@article.id}/patches")
|
|
|
|
[res, body] = yield request.getAsync { url, json: true }
|
|
|
|
expect(res.statusCode).toBe(200)
|
|
|
|
expect(body.length).toBe(1)
|
|
|
|
expect(body[0]._id).toBe(patchID)
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'accepts all patchable collections', utils.wrap (done) ->
|
|
|
|
admin = yield utils.initAdmin()
|
|
|
|
yield utils.loginUser(admin)
|
|
|
|
|
|
|
|
targets = [
|
|
|
|
{ collection: 'achievement', modelPromise: utils.makeAchievement() }
|
|
|
|
{ collection: 'article', modelPromise: utils.makeArticle() }
|
|
|
|
{ collection: 'campaign', modelPromise: utils.makeCampaign() }
|
|
|
|
{ collection: 'course', modelPromise: utils.makeCourse() }
|
|
|
|
{ collection: 'level', modelPromise: utils.makeLevel() }
|
|
|
|
{ collection: 'level_component', modelPromise: utils.makeLevelComponent() }
|
|
|
|
{ collection: 'level_system', modelPromise: utils.makeLevelSystem() }
|
|
|
|
{ collection: 'poll', modelPromise: utils.makePoll() }
|
|
|
|
{ collection: 'thang_type', modelPromise: utils.makeThangType() }
|
|
|
|
]
|
|
|
|
|
|
|
|
# concisely test everything in parallel
|
|
|
|
promises = targets.map((target) => co =>
|
|
|
|
model = yield target.modelPromise
|
|
|
|
json = {
|
|
|
|
commitMessage: 'Accept this patch!'
|
|
|
|
delta: { name: ['test'] }
|
|
|
|
target:
|
|
|
|
id: model.id
|
|
|
|
collection: target.collection
|
|
|
|
}
|
|
|
|
[res, body] = yield request.postAsync { @url, json }
|
|
|
|
expect(res.statusCode).toBe(201)
|
|
|
|
)
|
|
|
|
yield promises
|
|
|
|
count = yield Patch.count()
|
|
|
|
expect(count).toBe(targets.length) # make sure all patches got created
|
|
|
|
done()
|
2014-06-30 22:16:26 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
describe 'PUT /db/:collection/:handle/watch', ->
|
|
|
|
beforeEach makeArticle
|
|
|
|
|
|
|
|
it 'adds the user to the list of watchers idempotently when body is {on: true}', utils.wrap (done) ->
|
|
|
|
url = getURL("/db/article/#{@article.id}/watch")
|
|
|
|
[res, body] = yield request.putAsync({url, json: {on: true}})
|
|
|
|
expect(body.watchers[1]).toBeDefined()
|
|
|
|
expect(_.last(body.watchers)).toBe(@user.id)
|
|
|
|
previousWatchers = body.watchers
|
|
|
|
[res, body] = yield request.putAsync({url, json: {on: true}})
|
|
|
|
expect(_.isEqual(previousWatchers, body.watchers)).toBe(true)
|
|
|
|
done()
|
2014-06-30 22:16:26 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'removes user from the list of watchers when body is {on: false}', utils.wrap (done) ->
|
|
|
|
url = getURL("/db/article/#{@article.id}/watch")
|
|
|
|
[res, body] = yield request.putAsync({url, json: {on: true}})
|
|
|
|
expect(_.contains(body.watchers, @user.id)).toBe(true)
|
|
|
|
[res, body] = yield request.putAsync({url, json: {on: false}})
|
|
|
|
expect(_.contains(body.watchers, @user.id)).toBe(false)
|
|
|
|
done()
|
|
|
|
|
|
|
|
|
|
|
|
describe 'PUT /db/patch/:handle/status', ->
|
|
|
|
beforeEach makeArticle
|
|
|
|
|
|
|
|
beforeEach utils.wrap (done) ->
|
|
|
|
[res, body] = yield request.postAsync { url: utils.getURL('/db/patch'), @json }
|
|
|
|
@patchID = body._id
|
|
|
|
@url = utils.getURL("/db/patch/#{@patchID}/status")
|
|
|
|
done()
|
2014-06-30 22:16:26 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'withdraws the submitter\'s patch', utils.wrap (done) ->
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'withdrawn'}}
|
|
|
|
expect(res.statusCode).toBe(200)
|
|
|
|
expect(body.status).toBe('withdrawn')
|
2016-09-16 16:19:39 -04:00
|
|
|
yield new Promise((resolve) -> setTimeout(resolve, 50))
|
2016-09-07 19:15:54 -04:00
|
|
|
article = yield Article.findById(@article.id)
|
|
|
|
expect(article.get('patches').length).toBe(0)
|
|
|
|
done()
|
2014-06-30 22:16:26 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'does not allow the submitter to reject or accept the pull request', utils.wrap (done) ->
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'rejected'}}
|
|
|
|
expect(res.statusCode).toBe(403)
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'accepted'}}
|
|
|
|
expect(res.statusCode).toBe(403)
|
|
|
|
patch = yield Patch.findById(@patchID)
|
|
|
|
expect(patch.get('status')).toBe('pending')
|
|
|
|
done()
|
2014-04-08 22:26:19 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'allows the recipient to accept or reject the pull request', utils.wrap (done) ->
|
|
|
|
yield utils.loginUser(@creator)
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'rejected'}}
|
|
|
|
expect(res.statusCode).toBe(200)
|
|
|
|
patch = yield Patch.findById(@patchID)
|
|
|
|
expect(patch.get('status')).toBe 'rejected'
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'accepted'}}
|
|
|
|
expect(body.status).toBe('accepted')
|
|
|
|
expect(body.acceptor).toBe(@creator.id)
|
|
|
|
done()
|
2014-06-28 11:44:07 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'keeps track of amount of submitted and accepted patches', utils.wrap (done) ->
|
|
|
|
yield utils.loginUser(@creator)
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'accepted'}}
|
|
|
|
expect(res.statusCode).toBe(200)
|
|
|
|
yield new Promise((resolve) -> setTimeout(resolve, 100))
|
|
|
|
user = yield User.findById(@user.id)
|
|
|
|
expect(user.get 'stats.patchesSubmitted').toBe 1
|
|
|
|
expect(user.get 'stats.patchesContributed').toBe 1
|
|
|
|
expect(user.get 'stats.totalMiscPatches').toBe 1
|
|
|
|
expect(user.get 'stats.articleMiscPatches').toBe 1
|
|
|
|
expect(user.get 'stats.totalTranslationPatches').toBeUndefined()
|
|
|
|
done()
|
2014-07-23 14:00:28 -04:00
|
|
|
|
2016-09-07 19:15:54 -04:00
|
|
|
it 'does not allow the recipient to withdraw the pull request', utils.wrap (done) ->
|
|
|
|
yield utils.loginUser(@creator)
|
|
|
|
[res, body] = yield request.putAsync {@url, json: {status: 'withdrawn'}}
|
|
|
|
expect(res.statusCode).toBe(403)
|
|
|
|
done()
|
2016-08-18 16:29:52 -04:00
|
|
|
|
|
|
|
it 'only allows artisans and admins to set patch status for courses', utils.wrap (done) ->
|
|
|
|
submitter = yield utils.initUser()
|
|
|
|
course = yield utils.makeCourse()
|
|
|
|
patch = new Patch({
|
|
|
|
delta: { name: 'test' }
|
|
|
|
target: { collection: 'course', id: course._id, original: course._id }
|
|
|
|
creator: submitter._id
|
|
|
|
status: 'pending'
|
|
|
|
commitMessage: '...'
|
|
|
|
})
|
|
|
|
yield patch.save()
|
|
|
|
anotherUser = yield utils.initUser()
|
|
|
|
yield utils.loginUser(anotherUser)
|
|
|
|
json = { status: 'rejected' }
|
|
|
|
[res, body] = yield request.putAsync({ url: utils.getURL("/db/patch/#{patch.id}/status"), json})
|
|
|
|
expect(res.statusCode).toBe(403)
|
|
|
|
done()
|