From fc1f6ba0b9c5fde15cc1abbfe8d8f6ebe8190c55 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 11 May 2015 15:43:35 +0200 Subject: [PATCH 01/10] fix(emails): always use main site as base url --- website/src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/utils.js b/website/src/utils.js index cefb9cab8c..37783f56ce 100644 --- a/website/src/utils.js +++ b/website/src/utils.js @@ -61,7 +61,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso var mailingInfoArray = Array.isArray(mailingInfoArray) ? mailingInfoArray : [mailingInfoArray]; var variables = [ - {name: 'BASE_URL', content: baseUrl} + {name: 'BASE_URL', content: 'https://habitrpg.com'} ].concat(variables || []); // It's important to pass at least a user with its `preferences` as we need to check if he unsubscribed From e966de7bf0fd0f4eecff7ace286d4863565bbd7b Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 11 May 2015 16:54:44 +0200 Subject: [PATCH 02/10] feat(emails): add field to keep track of weekly recap emails --- website/src/models/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/website/src/models/user.js b/website/src/models/user.js index 61f44e1724..63e8cbd8ea 100644 --- a/website/src/models/user.js +++ b/website/src/models/user.js @@ -148,6 +148,7 @@ var UserSchema = new Schema({ recaptureEmailsPhase: {type: Number, 'default': 0}, // Needed to track the tip to send inside the email weeklyRecapEmailsPhase: {type: Number, 'default': 0}, + lastWeeklyRecap: {type: Date, 'default': Date.now}, communityGuidelinesAccepted: {type: Boolean, 'default': false}, cronCount: {type:Number, 'default':0} }, From 30fd8e26e6d6078d36975138fa130b235ade5969 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 11 May 2015 17:02:36 +0200 Subject: [PATCH 03/10] revert last 2 commits --- website/src/models/user.js | 1 - website/src/utils.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/website/src/models/user.js b/website/src/models/user.js index 63e8cbd8ea..61f44e1724 100644 --- a/website/src/models/user.js +++ b/website/src/models/user.js @@ -148,7 +148,6 @@ var UserSchema = new Schema({ recaptureEmailsPhase: {type: Number, 'default': 0}, // Needed to track the tip to send inside the email weeklyRecapEmailsPhase: {type: Number, 'default': 0}, - lastWeeklyRecap: {type: Date, 'default': Date.now}, communityGuidelinesAccepted: {type: Boolean, 'default': false}, cronCount: {type:Number, 'default':0} }, diff --git a/website/src/utils.js b/website/src/utils.js index 37783f56ce..cefb9cab8c 100644 --- a/website/src/utils.js +++ b/website/src/utils.js @@ -61,7 +61,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso var mailingInfoArray = Array.isArray(mailingInfoArray) ? mailingInfoArray : [mailingInfoArray]; var variables = [ - {name: 'BASE_URL', content: 'https://habitrpg.com'} + {name: 'BASE_URL', content: baseUrl} ].concat(variables || []); // It's important to pass at least a user with its `preferences` as we need to check if he unsubscribed From c3bb6b88fa553d74536bf3746eb3884486250d6a Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 11 May 2015 17:21:57 +0200 Subject: [PATCH 04/10] fix(tests): temporarily skip test --- test/api/groups.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 0d392ea1bd..38c697bf19 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -111,7 +111,7 @@ describe "Groups", -> async.map members, joinGuild, (err, results) -> cb() ], done - it "includes user in public group member list when user is a member", (done) -> + it.skip "includes user in public group member list when user is a member", (done) -> request.get(baseURL + "/groups/" + guild._id) .end (res) -> From ae8b1704461cb64103dfbce517a16b8786831335 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 11 May 2015 20:44:52 +0200 Subject: [PATCH 05/10] fix(emails): remove base url from server --- website/src/controllers/groups.js | 22 +++++++++++----------- website/src/controllers/members.js | 2 +- website/src/utils.js | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/website/src/controllers/groups.js b/website/src/controllers/groups.js index 465de6ec08..f09b601cf9 100644 --- a/website/src/controllers/groups.js +++ b/website/src/controllers/groups.js @@ -325,7 +325,7 @@ api.flagChatMessage = function(req, res, next){ group.markModified('chat'); group.save(function(err,_saved){ if(err) return next(err); - var addressesToSendTo = JSON.parse(nconf.get('FLAG_REPORT_EMAIL')); + var addressesToSendTo = nconf.get('FLAG_REPORT_EMAIL'); if(Array.isArray(addressesToSendTo)){ addressesToSendTo = addressesToSendTo.map(function(email){ @@ -342,17 +342,17 @@ api.flagChatMessage = function(req, res, next){ {name: "REPORTER_USERNAME", content: user.profile.name}, {name: "REPORTER_UUID", content: user._id}, {name: "REPORTER_EMAIL", content: user.auth.local ? user.auth.local.email : ((user.auth.facebook && user.auth.facebook.emails && user.auth.facebook.emails[0]) ? user.auth.facebook.emails[0].value : null)}, - {name: "REPORTER_MODAL_URL", content: "https://habitrpg.com/static/front/#?memberId=" + user._id}, + {name: "REPORTER_MODAL_URL", content: "/static/front/#?memberId=" + user._id}, {name: "AUTHOR_USERNAME", content: message.user}, {name: "AUTHOR_UUID", content: message.uuid}, {name: "AUTHOR_EMAIL", content: author.auth.local ? author.auth.local.email : ((author.auth.facebook && author.auth.facebook.emails && author.auth.facebook.emails[0]) ? author.auth.facebook.emails[0].value : null)}, - {name: "AUTHOR_MODAL_URL", content: "https://habitrpg.com/static/front/#?memberId=" + message.uuid}, + {name: "AUTHOR_MODAL_URL", content: "/static/front/#?memberId=" + message.uuid}, {name: "GROUP_NAME", content: group.name}, {name: "GROUP_TYPE", content: group.type}, {name: "GROUP_ID", content: group._id}, - {name: "GROUP_URL", content: group._id == 'habitrpg' ? (nconf.get('BASE_URL') + '/#/options/groups/tavern') : (group.type === 'guild' ? (nconf.get('BASE_URL')+ '/#/options/groups/guilds/' + group._id) : 'party')}, + {name: "GROUP_URL", content: group._id == 'habitrpg' ? '/#/options/groups/tavern' : (group.type === 'guild' ? ('/#/options/groups/guilds/' + group._id) : 'party')}, ]); return res.send(204); @@ -592,12 +592,12 @@ var inviteByUUIDs = function(uuids, group, req, res, next){ if(group.type == 'guild'){ emailVars.push( {name: 'GUILD_NAME', content: group.name}, - {name: 'GUILD_URL', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'} + {name: 'GUILD_URL', content: '/#/options/groups/guilds/public'} ); }else{ emailVars.push( {name: 'PARTY_NAME', content: group.name}, - {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} + {name: 'PARTY_URL', content: '/#/options/groups/party'} ) } @@ -639,7 +639,7 @@ var inviteByEmails = function(invites, group, req, res, next){ } // yeah, it supports guild too but for backward compatibility we'll use partyInvite as query - var link = nconf.get('BASE_URL')+'?partyInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); + var link = '?partyInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); var inviterVars = utils.getUserInfo(res.locals.user, ['name', 'email']); var variables = [ @@ -704,8 +704,8 @@ api.removeMember = function(req, res, next){ utils.txnEmail(removedUser, ('kicked-from-' + group.type), [ {name: 'GROUP_NAME', content: group.name}, {name: 'MESSAGE', content: message}, - {name: 'GUILDS_LINK', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'}, - {name: 'PARTY_WANTED_GUILD', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'} + {name: 'GUILDS_LINK', content: '/#/options/groups/guilds/public'}, + {name: 'PARTY_WANTED_GUILD', content: '/#/options/groups/guilds/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'} ]); } } @@ -855,7 +855,7 @@ questStart = function(req, res, next) { }); utils.txnEmail(usersToEmail, 'quest-started', [ - {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} + {name: 'PARTY_URL', content: '/#/options/groups/party'} ]); _.each(groupClone.members, function(user){ @@ -915,7 +915,7 @@ api.questAccept = function(req, res, next) { {name: 'QUEST_NAME', content: quest.text()}, {name: 'INVITER', content: inviterVars.name}, {name: 'REPLY_TO_ADDRESS', content: inviterVars.email}, - {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} + {name: 'PARTY_URL', content: '/#/options/groups/party'} ]); questStart(req,res,next); diff --git a/website/src/controllers/members.js b/website/src/controllers/members.js index 9102df985a..8001d29db7 100644 --- a/website/src/controllers/members.js +++ b/website/src/controllers/members.js @@ -72,7 +72,7 @@ api.sendPrivateMessage = function(req, res, next){ if(fetchedMember.preferences.emailNotifications.newPM !== false){ utils.txnEmail(fetchedMember, 'new-pm', [ {name: 'SENDER', content: utils.getUserInfo(res.locals.user, ['name']).name}, - {name: 'PMS_INBOX_URL', content: nconf.get('BASE_URL') + '/#/options/groups/inbox'} + {name: 'PMS_INBOX_URL', content: '/#/options/groups/inbox'} ]); } diff --git a/website/src/utils.js b/website/src/utils.js index cefb9cab8c..00ee9c106b 100644 --- a/website/src/utils.js +++ b/website/src/utils.js @@ -87,7 +87,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso }, { name: 'RECIPIENT_UNSUB_URL', - content: baseUrl + '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({ + content: '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({ _id: mailingInfo._id, email: mailingInfo.email })) @@ -113,7 +113,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso }, { name: 'RECIPIENT_UNSUB_URL', - content: baseUrl + '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({ + content: '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({ _id: temporaryPersonalVariables[singlePersonalVariables.rcpt]._id, email: singlePersonalVariables.rcpt })) From b663ff7101547b607e91562560aef4f4391ec143 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 11 May 2015 14:40:45 -0500 Subject: [PATCH 06/10] Skipping group tests while we sort out join issue --- test/api/groups.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 38c697bf19..03d87775be 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -5,7 +5,7 @@ diff = require("deep-diff") Group = require("../../website/src/models/group").model app = require("../../website/src/server") -describe "Groups", -> +describe.skip "Groups", -> group = undefined before (done) -> async.waterfall [ From 3c61b8dc4f07ce7a1637545f5006d1d1b5d6dfc0 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 11 May 2015 14:41:35 -0500 Subject: [PATCH 07/10] Add todo about re-enabling test --- test/api/groups.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 03d87775be..324a9d17ec 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -5,6 +5,7 @@ diff = require("deep-diff") Group = require("../../website/src/models/group").model app = require("../../website/src/server") +# @TODO: Re-enable when problems with https://github.com/HabitRPG/habitrpg/pull/4961 are sorted out describe.skip "Groups", -> group = undefined before (done) -> From d448ca3ac57524edff7f6df6f9a602dbfbe5ddaa Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 11 May 2015 22:13:31 +0200 Subject: [PATCH 08/10] fix(groups): do not try to add members to a party when it does not exists --- website/src/controllers/groups.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/website/src/controllers/groups.js b/website/src/controllers/groups.js index f09b601cf9..19e268eb50 100644 --- a/website/src/controllers/groups.js +++ b/website/src/controllers/groups.js @@ -136,7 +136,13 @@ api.get = function(req, res, next) { populateQuery(gid, q); q.exec(function(err, group){ if (err) return next(err); - if (!group && gid!=='party') return res.json(404,{err: "Group not found or you don't have access."}); + if(!group){ + if(gid !== 'party') return res.json(404,{err: "Group not found or you don't have access."}); + + // Don't send a 404 when querying for a party even if it doesn't exist + // so that users with no party don't get a 404 on every access to the site + return res.json(group); + } //Since we have a limit on how many members are populate to the group, we want to make sure the user is always in the group var userInGroup = _.find(group.members, function(member){ return member._id == user._id; }); //If the group is private or the group is a party, then the user must be a member of the group based on access restrictions above From faa897e4aec10e11502ca888b1d339c16c609d63 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 11 May 2015 17:29:46 -0500 Subject: [PATCH 09/10] Re-enable skipped test --- test/api/groups.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 324a9d17ec..38c697bf19 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -5,8 +5,7 @@ diff = require("deep-diff") Group = require("../../website/src/models/group").model app = require("../../website/src/server") -# @TODO: Re-enable when problems with https://github.com/HabitRPG/habitrpg/pull/4961 are sorted out -describe.skip "Groups", -> +describe "Groups", -> group = undefined before (done) -> async.waterfall [ From ff41a2c240ae76687dde9363456bbdb96fcbc8f6 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Tue, 12 May 2015 08:08:55 -0500 Subject: [PATCH 10/10] Refactor group tests --- test/api/groups.coffee | 688 +++++++++++++++--------------- website/src/controllers/groups.js | 6 +- 2 files changed, 352 insertions(+), 342 deletions(-) diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 38c697bf19..23d79fcf98 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -6,31 +6,17 @@ Group = require("../../website/src/models/group").model app = require("../../website/src/server") describe "Groups", -> - group = undefined - before (done) -> - async.waterfall [ - (cb) -> - registerNewUser(cb, true) - , (user, cb) -> - request.post(baseURL + "/groups").send( - name: "TestGroup" - type: "party" - ).end (res) -> - expectCode res, 200 - group = res.body - expect(group.members.length).to.equal 1 - expect(group.leader).to.equal user._id - done() - ] describe "Guilds", -> before (done) -> - User.findByIdAndUpdate user._id, - $set: - "balance": 4 - , (err, _user) -> - done() + registerNewUser -> + User.findByIdAndUpdate user._id, + $set: + "balance": 4 + , (err, _user) -> + done() + , true describe "Private Guilds", -> guild = undefined @@ -111,30 +97,58 @@ describe "Groups", -> async.map members, joinGuild, (err, results) -> cb() ], done - it.skip "includes user in public group member list when user is a member", (done) -> - - request.get(baseURL + "/groups/" + guild._id) - .end (res) -> - g = res.body - expect(g.members.length).to.equal 15 - userInGroup = _.find g.members, (member) -> return member._id == user._id - expect(userInGroup).to.exist - done() - - - it "excludes user in public group member list when user is not a member", (done) -> - #Remove user from group - request.post(baseURL + "/groups/" + guild._id + "/leave") - .end (res) -> - #Verfiy that when a user query's for a group they are in the group if they are a member - request.get(baseURL + "/groups/" + guild._id) - .end (res) -> - g = res.body - expect(g.members.length).to.equal 15 - userInGroup = _.find g.members, (member) -> return member._id == user._id - expect(userInGroup).to.not.exist + context "is a member", -> + before (done) -> + registerNewUser -> + request.post(baseURL + "/groups/" + guild._id + "/join") + .end -> done() + , true + + it "includes user in public group member list", (done) -> + + request.get(baseURL + "/groups/" + guild._id) + .end (res) -> + g = res.body + expect(g.members.length).to.equal 15 + userInGroup = _.find g.members, (member) -> return member._id == user._id + expect(userInGroup).to.be.ok + done() + + + context "is not a member", -> + + before (done) -> + registerNewUser done, true + + it "excludes user in public group member list", (done) -> + request.get(baseURL + "/groups/" + guild._id) + .end (res) -> + g = res.body + expect(g.members.length).to.equal 15 + userInGroup = _.find g.members, (member) -> return member._id == user._id + expect(userInGroup).to.not.be.ok + done() + describe "Party", -> + + group = undefined + before (done) -> + async.waterfall [ + (cb) -> + registerNewUser(cb, true) + , (user, cb) -> + request.post(baseURL + "/groups").send( + name: "TestGroup" + type: "party" + ).end (res) -> + expectCode res, 200 + group = res.body + expect(group.members.length).to.equal 1 + expect(group.leader).to.equal user._id + done() + ] + it "can be found by querying for party", (done) -> request.get(baseURL + "/groups/").send( type: "party" @@ -142,8 +156,6 @@ describe "Groups", -> expectCode res, 200 party = res.body[0] - console.log("*******") - console.log(party.quest) expect(party._id).to.equal group._id expect(party.leader).to.equal user._id expect(party.name).to.equal group.name @@ -201,7 +213,6 @@ describe "Groups", -> ).end (res) -> expectCode res, 200 message = res.body[0] - console.log(message) expect(message.id).to.equal chat.id expect(message.timestamp).to.equal chat.timestamp expect(message.likes).to.deep.equal chat.likes @@ -228,54 +239,186 @@ describe "Groups", -> expect(body.err).to.equal "Message not found!" done() - describe "Quests", -> - party = undefined - participating = [] - notParticipating = [] - before (done) -> - # Tavern boss, side-by-side - Group.update( - _id: "habitrpg" - , - $set: - quest: - key: "dilatory" - active: true - progress: - hp: shared.content.quests.dilatory.boss.hp - rage: 0 - ).exec() + describe "Quests", -> + party = undefined + participating = [] + notParticipating = [] + before (done) -> + # Tavern boss, side-by-side + Group.update( + _id: "habitrpg" + , + $set: + quest: + key: "dilatory" + active: true + progress: + hp: shared.content.quests.dilatory.boss.hp + rage: 0 + ).exec() - # Tally some progress for later. Later we want to test that progress made before the quest began gets - # counted after the quest starts - async.waterfall [ - (cb) -> - request.post(baseURL + '/user/tasks').send({ - type: 'daily' - text: 'daily one' - }).end (res) -> - cb() - (cb) -> - request.post(baseURL + '/user/tasks').send({ - type: 'daily' - text: 'daily two' - }).end (res) -> - cb() - (cb) -> - User.findByIdAndUpdate user._id, - $set: - "stats.lvl": 50 - , (err, _user) -> - cb(null, _user) - (_user, cb) -> - user = _user + # Tally some progress for later. Later we want to test that progress made before the quest began gets + # counted after the quest starts + async.waterfall [ + (cb) -> + request.post(baseURL + '/user/tasks').send({ + type: 'daily' + text: 'daily one' + }).end (res) -> + cb() + (cb) -> + request.post(baseURL + '/user/tasks').send({ + type: 'daily' + text: 'daily two' + }).end (res) -> + cb() + (cb) -> + User.findByIdAndUpdate user._id, + $set: + "stats.lvl": 50 + , (err, _user) -> + cb(null, _user) + (_user, cb) -> + user = _user + request.post(baseURL + "/user/batch-update").send([ + { + op: "score" + params: + direction: "up" + id: user.dailys[0].id + } + { + op: "score" + params: + direction: "up" + id: user.dailys[0].id + } + { + op: "update" + body: + "stats.lvl": 50 + } + ]).end (res) -> + user = res.body + expect(user.party.quest.progress.up).to.be.above 0 + + # Invite some members + async.waterfall [ + + # Register new users + (cb) -> + registerManyUsers 3, cb + + # Send them invitations + (_party, cb) -> + party = _party + inviteURL = baseURL + "/groups/" + group._id + "/invite" + async.parallel [ + (cb2) -> + request.post(inviteURL).send( + uuids: [party[0]._id] + ).end -> + cb2() + (cb2) -> + request.post(inviteURL).send( + uuids: [party[1]._id] + ).end -> + cb2() + (cb2) -> + request.post(inviteURL).send( + uuids: [party[2]._id] + ).end (res)-> + cb2() + ], cb + + # Accept / Reject + (results, cb) -> + + # series since they'll be modifying the same group record + series = _.reduce(party, (m, v, i) -> + m.push (cb2) -> + request.post(baseURL + "/groups/" + group._id + "/join").set("X-API-User", party[i]._id).set("X-API-Key", party[i].apiToken).end -> + cb2() + m + , []) + async.series series, cb + + # Make sure the invites stuck + (whatever, cb) -> + Group.findById group._id, (err, g) -> + group = g + expect(g.members.length).to.equal 4 + cb() + + ], -> + + # Start the quest + async.waterfall [ + (cb) -> + request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (res) -> + expectCode res, 400 + User.findByIdAndUpdate user._id, + $set: + "items.quests.vice3": 1 + , cb + + (_user, cb) -> + request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (res) -> + expectCode res, 200 + Group.findById group._id, cb + + (_group, cb) -> + expect(_group.quest.key).to.equal "vice3" + expect(_group.quest.active).to.equal false + request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[0]._id).set("X-API-Key", party[0].apiToken).end -> + request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[1]._id).set("X-API-Key", party[1].apiToken).end (res) -> + request.post(baseURL + "/groups/" + group._id + "/questReject").set("X-API-User", party[2]._id).set("X-API-Key", party[2].apiToken).end (res) -> + group = res.body + expect(group.quest.active).to.equal true + cb() + + ], done + ] + + it "Casts a spell", (done) -> + mp = user.stats.mp + request.get(baseURL + "/members/" + party[0]._id).end (res) -> + party[0] = res.body + request.post(baseURL + "/user/class/cast/snowball?targetType=user&targetId=" + party[0]._id).end (res) -> + + #expect(res.body.stats.mp).to.be.below(mp); + request.get(baseURL + "/members/" + party[0]._id).end (res) -> + member = res.body + expect(member.achievements.snowball).to.equal 1 + expect(member.stats.buffs.snowball).to.exist + difference = diff(member, party[0]) + expect(_.size(difference)).to.equal 2 + + # level up user so str is > 0 + request.put(baseURL + "/user").send("stats.lvl": 5).end (res) -> + + # Refill mana so user can cast + request.put(baseURL + "/user").send("stats.mp": 100).end (res) -> + request.post(baseURL + "/user/class/cast/valorousPresence?targetType=party").end (res) -> + request.get(baseURL + "/members/" + member._id).end (res) -> + expect(res.body.stats.buffs.str).to.be.above 0 + expect(diff(res.body, member).length).to.equal 1 + done() + + it "Doesn't include people who aren't participating", (done) -> + request.get(baseURL + "/groups/" + group._id).end (res) -> + expect(_.size(res.body.quest.members)).to.equal 3 + done() + + xit "Hurts the boss", (done) -> + request.post(baseURL + "/user/batch-update").end (res) -> + user = res.body + up = user.party.quest.progress.up + expect(up).to.be.above 0 + + #{op:'score',params:{direction:'up',id:user.dailys[3].id}}, // leave one daily undone so Trapper hurts party + # set day to yesterday, cron will then be triggered on next action request.post(baseURL + "/user/batch-update").send([ - { - op: "score" - params: - direction: "up" - id: user.dailys[0].id - } { op: "score" params: @@ -285,270 +428,137 @@ describe "Groups", -> { op: "update" body: - "stats.lvl": 50 + lastCron: moment().subtract(1, "days") } ]).end (res) -> - user = res.body - expect(user.party.quest.progress.up).to.be.above 0 + expect(res.body.party.quest.progress.up).to.be.above up + request.post(baseURL + "/user/batch-update").end -> + request.get(baseURL + "/groups/party").end (res) -> - # Invite some members - async.waterfall [ + # Check boss damage + async.waterfall [ + (cb) -> + async.parallel [ - # Register new users - (cb) -> - registerManyUsers 3, cb + #tavern boss + (cb2) -> + Group.findById "habitrpg", + quest: 1 + , (err, tavern) -> + expect(tavern.quest.progress.hp).to.be.below shared.content.quests.dilatory.boss.hp + expect(tavern.quest.progress.rage).to.be.above 0 + cb2() - # Send them invitations - (_party, cb) -> - party = _party - inviteURL = baseURL + "/groups/" + group._id + "/invite" - async.parallel [ - (cb2) -> - request.post(inviteURL).send( - uuids: [party[0]._id] - ).end -> - cb2() - (cb2) -> - request.post(inviteURL).send( - uuids: [party[1]._id] - ).end -> - cb2() - (cb2) -> - request.post(inviteURL).send( - uuids: [party[2]._id] - ).end (res)-> - cb2() - ], cb - - # Accept / Reject - (results, cb) -> - - # series since they'll be modifying the same group record - series = _.reduce(party, (m, v, i) -> - m.push (cb2) -> - request.post(baseURL + "/groups/" + group._id + "/join").set("X-API-User", party[i]._id).set("X-API-Key", party[i].apiToken).end -> - cb2() - m - , []) - async.series series, cb - - # Make sure the invites stuck - (whatever, cb) -> - Group.findById group._id, (err, g) -> - group = g - expect(g.members.length).to.equal 4 - cb() - - ], -> - - # Start the quest - async.waterfall [ - (cb) -> - request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (res) -> - expectCode res, 400 - User.findByIdAndUpdate user._id, - $set: - "items.quests.vice3": 1 - , cb - - (_user, cb) -> - request.post(baseURL + "/groups/" + group._id + "/questAccept?key=vice3").end (res) -> - expectCode res, 200 - Group.findById group._id, cb - - (_group, cb) -> - expect(_group.quest.key).to.equal "vice3" - expect(_group.quest.active).to.equal false - request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[0]._id).set("X-API-Key", party[0].apiToken).end -> - request.post(baseURL + "/groups/" + group._id + "/questAccept").set("X-API-User", party[1]._id).set("X-API-Key", party[1].apiToken).end (res) -> - request.post(baseURL + "/groups/" + group._id + "/questReject").set("X-API-User", party[2]._id).set("X-API-Key", party[2].apiToken).end (res) -> - group = res.body - expect(group.quest.active).to.equal true - cb() - - ], done - ] - - it "Casts a spell", (done) -> - mp = user.stats.mp - request.get(baseURL + "/members/" + party[0]._id).end (res) -> - party[0] = res.body - request.post(baseURL + "/user/class/cast/snowball?targetType=user&targetId=" + party[0]._id).end (res) -> - - #expect(res.body.stats.mp).to.be.below(mp); - request.get(baseURL + "/members/" + party[0]._id).end (res) -> - member = res.body - expect(member.achievements.snowball).to.equal 1 - expect(member.stats.buffs.snowball).to.exist - difference = diff(member, party[0]) - expect(_.size(difference)).to.equal 2 - - # level up user so str is > 0 - request.put(baseURL + "/user").send("stats.lvl": 5).end (res) -> - - # Refill mana so user can cast - request.put(baseURL + "/user").send("stats.mp": 100).end (res) -> - request.post(baseURL + "/user/class/cast/valorousPresence?targetType=party").end (res) -> - request.get(baseURL + "/members/" + member._id).end (res) -> - expect(res.body.stats.buffs.str).to.be.above 0 - expect(diff(res.body, member).length).to.equal 1 - done() - - it "Doesn't include people who aren't participating", (done) -> - request.get(baseURL + "/groups/" + group._id).end (res) -> - expect(_.size(res.body.quest.members)).to.equal 3 - done() - - xit "Hurts the boss", (done) -> - request.post(baseURL + "/user/batch-update").end (res) -> - user = res.body - up = user.party.quest.progress.up - expect(up).to.be.above 0 - - #{op:'score',params:{direction:'up',id:user.dailys[3].id}}, // leave one daily undone so Trapper hurts party - # set day to yesterday, cron will then be triggered on next action - request.post(baseURL + "/user/batch-update").send([ - { - op: "score" - params: - direction: "up" - id: user.dailys[0].id - } - { - op: "update" - body: - lastCron: moment().subtract(1, "days") - } - ]).end (res) -> - expect(res.body.party.quest.progress.up).to.be.above up - request.post(baseURL + "/user/batch-update").end -> - request.get(baseURL + "/groups/party").end (res) -> - - # Check boss damage - async.waterfall [ - (cb) -> - async.parallel [ - - #tavern boss - (cb2) -> - Group.findById "habitrpg", - quest: 1 - , (err, tavern) -> - expect(tavern.quest.progress.hp).to.be.below shared.content.quests.dilatory.boss.hp - expect(tavern.quest.progress.rage).to.be.above 0 - console.log tavernBoss: tavern.quest + # party boss + (cb2) -> + expect(res.body.quest.progress.hp).to.be.below shared.content.quests.vice3.boss.hp + _party = res.body.members + expect(_.find(_party, + _id: party[0]._id + ).stats.hp).to.be.below 50 + expect(_.find(_party, + _id: party[1]._id + ).stats.hp).to.be.below 50 + expect(_.find(_party, + _id: party[2]._id + ).stats.hp).to.be 50 cb2() + ], cb - # party boss - (cb2) -> - expect(res.body.quest.progress.hp).to.be.below shared.content.quests.vice3.boss.hp - _party = res.body.members - expect(_.find(_party, - _id: party[0]._id - ).stats.hp).to.be.below 50 - expect(_.find(_party, - _id: party[1]._id - ).stats.hp).to.be.below 50 - expect(_.find(_party, - _id: party[2]._id - ).stats.hp).to.be 50 - cb2() - ], cb + # Kill the boss + (whatever, cb) -> + async.waterfall [ - # Kill the boss - (whatever, cb) -> - async.waterfall [ + # tavern boss + (cb2) -> + expect(user.items.pets["MantisShrimp-Base"]).to.not.be.ok() + Group.update + _id: "habitrpg" + , + $set: + "quest.progress.hp": 0 + , cb2 - # tavern boss - (cb2) -> - expect(user.items.pets["MantisShrimp-Base"]).to.not.be.ok() - Group.update - _id: "habitrpg" - , - $set: - "quest.progress.hp": 0 - , cb2 + # party boss + (arg1, arg2, cb2) -> + expect(user.items.gear.owned.weapon_special_2).to.not.be.ok() + Group.findByIdAndUpdate group._id, + $set: + "quest.progress.hp": 0 + , cb2 + ], cb + (_group, cb) -> + # set day to yesterday, cron will then be triggered on next action + request.post(baseURL + "/user/batch-update").send([ + { + op: "score" + params: + direction: "up" + id: user.dailys[1].id + } + { + op: "update" + body: + lastCron: moment().subtract(1, "days") + } + ]).end -> + cb() - # party boss - (arg1, arg2, cb2) -> - expect(user.items.gear.owned.weapon_special_2).to.not.be.ok() - Group.findByIdAndUpdate group._id, - $set: - "quest.progress.hp": 0 - , cb2 - ], cb - (_group, cb) -> - # set day to yesterday, cron will then be triggered on next action - request.post(baseURL + "/user/batch-update").send([ - { - op: "score" - params: - direction: "up" - id: user.dailys[1].id - } - { - op: "update" - body: - lastCron: moment().subtract(1, "days") - } - ]).end -> - cb() + (cb) -> + request.post(baseURL + "/user/batch-update").end (res) -> + cb null, res.body - (cb) -> - request.post(baseURL + "/user/batch-update").end (res) -> - cb null, res.body + (_user, cb) -> - (_user, cb) -> + # need to load the user again, since tavern boss does update after user's cron + User.findById _user._id, cb + (_user, cb) -> + user = _user + Group.findById group._id, cb + (_group, cb) -> + cummExp = shared.content.quests.vice3.drop.exp + shared.content.quests.dilatory.drop.exp + cummGp = shared.content.quests.vice3.drop.gp + shared.content.quests.dilatory.drop.gp - # need to load the user again, since tavern boss does update after user's cron - User.findById _user._id, cb - (_user, cb) -> - user = _user - Group.findById group._id, cb - (_group, cb) -> - cummExp = shared.content.quests.vice3.drop.exp + shared.content.quests.dilatory.drop.exp - cummGp = shared.content.quests.vice3.drop.gp + shared.content.quests.dilatory.drop.gp + #//FIXME check that user got exp, but user is leveling up making the exp check difficult + # expect(user.stats.exp).to.be.above(cummExp); + # expect(user.stats.gp).to.be.above(cummGp); + async.parallel [ - #//FIXME check that user got exp, but user is leveling up making the exp check difficult - # expect(user.stats.exp).to.be.above(cummExp); - # expect(user.stats.gp).to.be.above(cummGp); - async.parallel [ + # Tavern Boss + (cb2) -> + Group.findById "habitrpg", (err, tavern) -> - # Tavern Boss - (cb2) -> - Group.findById "habitrpg", (err, tavern) -> + #use an explicit get because mongoose wraps the null in an object + expect(_.isEmpty(tavern.get("quest"))).to.equal true + expect(user.items.pets["MantisShrimp-Base"]).to.equal 5 + expect(user.items.mounts["MantisShrimp-Base"]).to.equal true + expect(user.items.eggs.Dragon).to.equal 2 + expect(user.items.hatchingPotions.Shade).to.equal 2 + cb2() + + # Party Boss + (cb2) -> #use an explicit get because mongoose wraps the null in an object - expect(_.isEmpty(tavern.get("quest"))).to.equal true - expect(user.items.pets["MantisShrimp-Base"]).to.equal 5 - expect(user.items.mounts["MantisShrimp-Base"]).to.equal true + expect(_.isEmpty(_group.get("quest"))).to.equal true + expect(user.items.gear.owned.weapon_special_2).to.equal true expect(user.items.eggs.Dragon).to.equal 2 expect(user.items.hatchingPotions.Shade).to.equal 2 - cb2() - # Party Boss - (cb2) -> - - #use an explicit get because mongoose wraps the null in an object - expect(_.isEmpty(_group.get("quest"))).to.equal true - expect(user.items.gear.owned.weapon_special_2).to.equal true - expect(user.items.eggs.Dragon).to.equal 2 - expect(user.items.hatchingPotions.Shade).to.equal 2 - - # need to fetch users to get updated data - async.parallel [ - (cb3) -> - User.findById party[0].id, (err, mbr) -> - expect(mbr.items.gear.owned.weapon_special_2).to.equal true - cb3() - (cb3) -> - User.findById party[1].id, (err, mbr) -> - expect(mbr.items.gear.owned.weapon_special_2).to.equal true - cb3() - (cb3) -> - User.findById party[2].id, (err, mbr) -> - expect(mbr.items.gear.owned.weapon_special_2).to.not.be.ok() - cb3() - ], cb2 - ], cb - ], done + # need to fetch users to get updated data + async.parallel [ + (cb3) -> + User.findById party[0].id, (err, mbr) -> + expect(mbr.items.gear.owned.weapon_special_2).to.equal true + cb3() + (cb3) -> + User.findById party[1].id, (err, mbr) -> + expect(mbr.items.gear.owned.weapon_special_2).to.equal true + cb3() + (cb3) -> + User.findById party[2].id, (err, mbr) -> + expect(mbr.items.gear.owned.weapon_special_2).to.not.be.ok() + cb3() + ], cb2 + ], cb + ], done diff --git a/website/src/controllers/groups.js b/website/src/controllers/groups.js index 19e268eb50..831a1bcb39 100644 --- a/website/src/controllers/groups.js +++ b/website/src/controllers/groups.js @@ -147,15 +147,15 @@ api.get = function(req, res, next) { var userInGroup = _.find(group.members, function(member){ return member._id == user._id; }); //If the group is private or the group is a party, then the user must be a member of the group based on access restrictions above if (group.privacy === 'private' || gid === 'party') { - //If the user is not in the group query, add them - if (!userInGroup) { group.members.push(user); } + //If the user is not in the group query, remove a user and add the current user + if (!userInGroup) { group.members.pop().push(user); } res.json(group); } else if ( group.privacy === "public" ) { //The group is public, we must do an extra check to see if the user is already in the group query //We must see how to check if a user is a member of a public group, so we requery var q2 = Group.findOne({ _id: group._id, privacy:'public', members: {$in:[user._id]} }); q2.exec(function(err, group2){ if (err) return next(err); - if (group2 && !userInGroup) { group.members.push(user); } + if (group2 && !userInGroup) { group.members.pop().push(user); } res.json(group); }); }