diff --git a/test/api/groups.coffee b/test/api/groups.coffee index 2daa783645..5240d4c4c4 100644 --- a/test/api/groups.coffee +++ b/test/api/groups.coffee @@ -11,7 +11,7 @@ describe "Guilds", -> registerNewUser -> User.findByIdAndUpdate user._id, $set: - "balance": 10 + "balance": 40 , (err, _user) -> done() , true @@ -150,6 +150,73 @@ describe "Guilds", -> expectCode res, 204 done() + it "deletes a group when the last member leaves", (done) -> + groupToDeleteAfterLeave = undefined + request.post(baseURL + "/groups").send( + name: "TestGroupToDeleteAfteLeave" + type: "guild" + privacy: "private" + ).end (res) -> + groupToDeleteAfterLeave = res.body + async.waterfall [ + (cb) -> + request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id + "/leave") + .end (res) -> + expectCode res, 204 + cb() + + (cb) -> + request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id) + .end (res) -> + expectCode res, 404 + cb() + ], done + + it "deletes all invites to a group when the last member leaves", (done) -> + groupToDeleteAfterLeave = undefined + userToRemoveInvite = undefined + request.post(baseURL + "/groups").send( + name: "TestGroupToDeleteAfteLeave" + type: "guild" + privacy: "private" + ).end (res) -> + groupToDeleteAfterLeave = res.body + async.waterfall [ + (cb) -> + registerManyUsers 1, cb + + (_members, cb) -> + userToRemoveInvite = _members[0] + inviteURL = baseURL + "/groups/" + groupToDeleteAfterLeave._id + "/invite" + request.post(inviteURL).send( + uuids: [userToRemoveInvite._id] + ) + .end -> + cb() + + (cb) -> + request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id + "/leave") + .end (res) -> + expectCode res, 204 + cb() + + (cb) -> + request.get(baseURL + '/user') + .set("X-API-User", userToRemoveInvite._id) + .set("X-API-Key", userToRemoveInvite.apiToken) + .end (err, res) -> + expectCode res, 200 + groupInvitation = _.find(res.body.invitations.guilds, {id: groupToDeleteAfterLeave._id}) + expect(groupInvitation).to.not.exist + cb() + + (cb) -> + request.post(baseURL + "/groups/" + groupToDeleteAfterLeave._id) + .end (res) -> + expectCode res, 404 + cb() + ], done + context "removing users groups", -> it "allows guild leaders to remove a member (but not themselves)", (done) -> guildToRemoveMember = undefined diff --git a/website/src/models/group.js b/website/src/models/group.js index 5f79f46a89..25129c3c9d 100644 --- a/website/src/models/group.js +++ b/website/src/models/group.js @@ -84,6 +84,31 @@ GroupSchema.pre('save', function(next){ next(); }) +GroupSchema.pre('remove', function(next) { + var group = this; + async.waterfall([ + function(cb) { + User.find({ + 'invitations.guilds.id': group._id + }, cb); + }, + function(users, cb) { + if (users) { + users.forEach(function (user, index, array) { + var i = _.findIndex(user.invitations.guilds, {id: group._id}); + user.invitations.guilds.splice(i, 1); + user.save(); + }); + } + cb(); + } + ], next); +}); + +GroupSchema.post('remove', function(group) { + firebase.deleteGroup(group._id); +}); + GroupSchema.methods.toJSON = function(){ var doc = this.toObject(); removeDuplicates(doc); @@ -358,8 +383,7 @@ GroupSchema.methods.leave = function(user, keep, mainCb){ if(typeof keep !== 'string') keep = 'keep-all'; // can be also 'remove-all' var group = this; - var groupWasRemoved = false; - + async.parallel([ // Remove user from group challenges function(cb){ @@ -404,11 +428,7 @@ GroupSchema.methods.leave = function(user, keep, mainCb){ group.type === 'party' || (group.type === 'guild' && group.privacy === 'private') )){ - // TODO remove invitations to this group - groupWasRemoved = true; - Group.remove({ - _id: group._id - }, cb); + group.remove(cb) }else{ // otherwise just remove a member var update = {$pull: {members: user._id}}; @@ -435,7 +455,6 @@ GroupSchema.methods.leave = function(user, keep, mainCb){ if(err) return mainCb(err); firebase.removeUserFromGroup(group._id, user._id); - if(groupWasRemoved) firebase.deleteGroup(group._id); return mainCb(); }); }; @@ -468,4 +487,4 @@ Group.count({_id: 'habitrpg'}, function(err, ct){ type: 'guild', privacy: 'public' }).save(); -}); \ No newline at end of file +});