Merge pull request #5799 from Alys/challenges-editable-by-admins-2015-08-16
allow Challenges to be edited, closed, and deleted by staff and moderators
This commit is contained in:
@@ -56,5 +56,8 @@
|
||||
"backToChallenges": "Back to all challenges",
|
||||
"prizeValue": "<%= gemcount %> <%= gemicon %> Prize",
|
||||
"clone": "Clone",
|
||||
"challengeNotEnoughGems": "You do not have enough gems to post this challenge."
|
||||
"challengeNotEnoughGems": "You do not have enough gems to post this challenge.",
|
||||
"noPermissionEditChallenge": "You don't have permissions to edit this challenge",
|
||||
"noPermissionDeleteChallenge": "You don't have permissions to delete this challenge",
|
||||
"noPermissionCloseChallenge": "You don't have permissions to close this challenge"
|
||||
}
|
||||
|
||||
+196
-59
@@ -10,7 +10,7 @@ describe "Challenges", ->
|
||||
updateTodo = undefined
|
||||
group = undefined
|
||||
|
||||
before (done) ->
|
||||
beforeEach (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
registerNewUser(cb, true)
|
||||
@@ -23,68 +23,123 @@ describe "Challenges", ->
|
||||
group = res.body
|
||||
expect(group.members.length).to.equal 1
|
||||
expect(group.leader).to.equal user._id
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
todos: [{
|
||||
type: "todo"
|
||||
text: "Challenge Todo 1"
|
||||
notes: "Challenge Notes"
|
||||
}]
|
||||
rewards: []
|
||||
habits: []
|
||||
).end (res) ->
|
||||
challenge = res.body
|
||||
done()
|
||||
]
|
||||
|
||||
it "Creates a challenge", (done) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
todos: [{
|
||||
type: "todo"
|
||||
text: "Challenge Todo 1"
|
||||
notes: "Challenge Notes"
|
||||
}, {
|
||||
type: "todo"
|
||||
text: "Challenge Todo 2"
|
||||
notes: "Challenge Notes"
|
||||
}]
|
||||
rewards: []
|
||||
habits: []
|
||||
official: true
|
||||
).end (res) ->
|
||||
expectCode res, 200
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
User.findById user._id, cb
|
||||
(cb) ->
|
||||
Challenge.findById res.body._id, cb
|
||||
], (err, results) ->
|
||||
_user = results[0]
|
||||
challenge = results[1]
|
||||
expect(_user.dailys[_user.dailys.length - 1].text).to.equal "Challenge Daily"
|
||||
updateTodo = _user.todos[_user.todos.length - 1]
|
||||
expect(updateTodo.text).to.equal "Challenge Todo 2"
|
||||
expect(challenge.official).to.equal false
|
||||
user = _user
|
||||
done()
|
||||
|
||||
it "User updates challenge notes", (done) ->
|
||||
updateTodo.notes = "User overriden notes"
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (res) ->
|
||||
done() # we'll do the check down below
|
||||
|
||||
it "Change challenge daily", (done) ->
|
||||
challenge.dailys[0].text = "Updated Daily"
|
||||
challenge.todos[0].notes = "Challenge Updated Todo Notes"
|
||||
request.post(baseURL + "/challenges/" + challenge._id).send(challenge).end (res) ->
|
||||
setTimeout (->
|
||||
User.findById user._id, (err, _user) ->
|
||||
expectCode res, 200
|
||||
expect(_user.dailys[_user.dailys.length - 1].text).to.equal "Updated Daily"
|
||||
expect(res.body.todos[0].notes).to.equal "Challenge Updated Todo Notes"
|
||||
expect(_user.todos[_user.todos.length - 1].notes).to.equal "User overriden notes"
|
||||
user = _user
|
||||
describe 'POST /challenge', ->
|
||||
|
||||
it "Creates a challenge", (done) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
todos: [{
|
||||
type: "todo"
|
||||
text: "Challenge Todo 1"
|
||||
notes: "Challenge Notes"
|
||||
}, {
|
||||
type: "todo"
|
||||
text: "Challenge Todo 2"
|
||||
notes: "Challenge Notes"
|
||||
}]
|
||||
rewards: []
|
||||
habits: []
|
||||
official: true
|
||||
).end (res) ->
|
||||
expectCode res, 200
|
||||
async.parallel [
|
||||
(cb) ->
|
||||
User.findById user._id, cb
|
||||
(cb) ->
|
||||
Challenge.findById res.body._id, cb
|
||||
], (err, results) ->
|
||||
user = results[0]
|
||||
challenge = results[1]
|
||||
expect(user.dailys[user.dailys.length - 1].text).to.equal "Challenge Daily"
|
||||
expect(challenge.official).to.equal false
|
||||
done()
|
||||
), 500 # we have to wait a while for users' tasks to be updated, called async on server
|
||||
|
||||
it "Shows user notes on challenge page", (done) ->
|
||||
request.get(baseURL + "/challenges/" + challenge._id + "/member/" + user._id).end (res) ->
|
||||
expect(res.body.todos[res.body.todos.length - 1].notes).to.equal "User overriden notes"
|
||||
done()
|
||||
describe 'POST /challenge/:cid', ->
|
||||
it "updates the notes on user's version of a challenge task's note without updating the challenge", (done) ->
|
||||
updateTodo = challenge.todos[0]
|
||||
updateTodo.notes = "User overriden notes"
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (res) ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
Challenge.findById challenge._id, cb
|
||||
, (chal, cb) ->
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes")
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.get(baseURL + "/user/tasks/" + updateTodo.id)
|
||||
.end (res) ->
|
||||
expect(res.body.notes).to.eql("User overriden notes")
|
||||
done()
|
||||
]
|
||||
|
||||
it "changes user's copy of challenge tasks when the challenge is updated", (done) ->
|
||||
challenge.dailys[0].text = "Updated Daily"
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
challenge = res.body
|
||||
expect(challenge.dailys[0].text).to.equal "Updated Daily"
|
||||
User.findById user._id, (err, _user) ->
|
||||
expectCode res, 200
|
||||
expect(_user.dailys[_user.dailys.length - 1].text).to.equal "Updated Daily"
|
||||
done()
|
||||
|
||||
it "does not changes user's notes on tasks when challenge task notes are updated", (done) ->
|
||||
challenge.todos[0].notes = "Challenge Updated Todo Notes"
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
challenge = res.body
|
||||
expect(challenge.todos[0].notes).to.equal "Challenge Updated Todo Notes"
|
||||
User.findById user._id, (err, _user) ->
|
||||
expectCode res, 200
|
||||
expect(_user.todos[_user.todos.length - 1].notes).to.equal "Challenge Notes"
|
||||
done()
|
||||
|
||||
|
||||
it "shows user notes on challenge page", (done) ->
|
||||
updateTodo = challenge.todos[0]
|
||||
updateTodo.notes = "User overriden notes"
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.put(baseURL + "/user/tasks/" + updateTodo.id).send(updateTodo).end (res) ->
|
||||
cb()
|
||||
, (cb) ->
|
||||
Challenge.findById challenge._id, cb
|
||||
, (chal, cb) ->
|
||||
expect(chal.todos[0].notes).to.eql("Challenge Notes")
|
||||
cb()
|
||||
, (cb) ->
|
||||
request.get(baseURL + "/challenges/" + challenge._id + "/member/" + user._id).end (res) ->
|
||||
expect(res.body.todos[res.body.todos.length - 1].notes).to.equal "User overriden notes"
|
||||
done()
|
||||
]
|
||||
|
||||
it "Complete To-Dos", (done) ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
@@ -116,7 +171,7 @@ describe "Challenges", ->
|
||||
done()
|
||||
), 100 # we need to wait for challenge to update user, it's a background job for perf reasons
|
||||
|
||||
it "Admin creates a challenge", (done) ->
|
||||
it "admin creates a challenge", (done) ->
|
||||
User.findByIdAndUpdate user._id,
|
||||
$set:
|
||||
"contributor.admin": true
|
||||
@@ -204,3 +259,85 @@ describe "Challenges", ->
|
||||
User.findById user._id, (err, _user) ->
|
||||
expect(_user.balance).to.equal 5.5
|
||||
done()
|
||||
|
||||
describe "non-owner permissions", () ->
|
||||
challenge = undefined
|
||||
|
||||
beforeEach (done) ->
|
||||
async.waterfall [
|
||||
(cb) ->
|
||||
request.post(baseURL + "/challenges").send(
|
||||
group: group._id
|
||||
name: 'challenge name'
|
||||
dailys: [
|
||||
type: "daily"
|
||||
text: "Challenge Daily"
|
||||
]
|
||||
).end (res) ->
|
||||
challenge = res.body
|
||||
cb()
|
||||
|
||||
(cb) ->
|
||||
registerNewUser(done, true)
|
||||
]
|
||||
|
||||
context "non-owner", () ->
|
||||
|
||||
it 'can not edit challenge', (done) ->
|
||||
challenge.name = 'foobar'
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to edit this challenge")
|
||||
done()
|
||||
|
||||
it 'can not close challenge', (done) ->
|
||||
request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id)
|
||||
.end (res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to close this challenge")
|
||||
done()
|
||||
|
||||
it 'can not delete challenge', (done) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id)
|
||||
.end (res) ->
|
||||
error = res.body.err
|
||||
|
||||
expect(error).to.eql("You don't have permissions to delete this challenge")
|
||||
done()
|
||||
|
||||
context "non-owner that is an admin", () ->
|
||||
|
||||
beforeEach (done) ->
|
||||
User.findByIdAndUpdate(user._id, { 'contributor.admin': true }, done)
|
||||
|
||||
it 'can edit challenge', (done) ->
|
||||
challenge.name = 'foobar'
|
||||
request.post(baseURL + "/challenges/" + challenge._id)
|
||||
.send(challenge)
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
Challenge.findById challenge._id, (err, chal) ->
|
||||
expect(chal.name).to.eql('foobar')
|
||||
done()
|
||||
|
||||
it 'can close challenge', (done) ->
|
||||
request.post(baseURL + "/challenges/" + challenge._id + "/close?uid=" + user._id)
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
User.findById user._id, (err, usr) ->
|
||||
expect(usr.achievements.challenges[0]).to.eql(challenge.name)
|
||||
done()
|
||||
|
||||
it 'can delete challenge', (done) ->
|
||||
request.del(baseURL + "/challenges/" + challenge._id)
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.not.exist
|
||||
request.get(baseURL + "/challenges/" + challenge._id)
|
||||
.end (res) ->
|
||||
error = res.body.err
|
||||
expect(error).to.eql("Challenge #{challenge._id} not found")
|
||||
done()
|
||||
|
||||
@@ -225,7 +225,7 @@ api.update = function(req, res, next){
|
||||
},
|
||||
function(_before, cb) {
|
||||
if (!_before) return cb('Challenge ' + cid + ' not found');
|
||||
if (_before.leader != user._id) return cb("You don't have permissions to edit this challenge");
|
||||
if (_before.leader != user._id && !user.contributor.admin) return cb(shared.i18n.t('noPermissionEditChallenge', req.language));
|
||||
// Update the challenge, since syncing will need the updated challenge. But store `before` we're going to do some
|
||||
// before-save / after-save comparison to determine if we need to sync to users
|
||||
before = _before;
|
||||
@@ -307,7 +307,7 @@ api['delete'] = function(req, res, next){
|
||||
},
|
||||
function(chal, cb){
|
||||
if (!chal) return cb('Challenge ' + cid + ' not found');
|
||||
if (chal.leader != user._id) return cb("You don't have permissions to edit this challenge");
|
||||
if (chal.leader != user._id && !user.contributor.admin) return cb(shared.i18n.t('noPermissionDeleteChallenge', req.language));
|
||||
if (chal.group != 'habitrpg') user.balance += chal.prize/4; // Refund gems to user if a non-tavern challenge
|
||||
user.save(cb);
|
||||
},
|
||||
@@ -336,7 +336,7 @@ api.selectWinner = function(req, res, next) {
|
||||
function(_chal, cb){
|
||||
chal = _chal;
|
||||
if (!chal) return cb('Challenge ' + cid + ' not found');
|
||||
if (chal.leader != user._id) return cb("You don't have permissions to edit this challenge");
|
||||
if (chal.leader != user._id && !user.contributor.admin) return cb(shared.i18n.t('noPermissionCloseChallenge', req.language));
|
||||
User.findById(req.query.uid, cb)
|
||||
},
|
||||
function(winner, cb){
|
||||
|
||||
@@ -30,7 +30,7 @@ script(type='text/ng-template', id='partials/options.social.challenges.detail.me
|
||||
|
||||
script(type='text/ng-template', id='partials/options.social.challenges.detail.html')
|
||||
// Edit button
|
||||
div(bindonce='challenge', ng-if='challenge.leader._id==user._id')
|
||||
div(bindonce='challenge', ng-if='challenge.leader._id==user._id || user.contributor.admin')
|
||||
div(ng-hide='challenge._locked==false')
|
||||
button.btn.btn-sm.btn-default(ng-click='edit(challenge)')=env.t('edit')
|
||||
button.btn.btn-sm.btn-success(ng-click='clone(challenge)')=env.t('clone')
|
||||
|
||||
Reference in New Issue
Block a user