diff --git a/app/templates/clans/clan-details.jade b/app/templates/clans/clan-details.jade index 49cca6d17..c5784ca4b 100644 --- a/app/templates/clans/clan-details.jade +++ b/app/templates/clans/clan-details.jade @@ -10,9 +10,9 @@ block content if isOwner button.btn.btn-sm.btn-warning Delete Clan else if isMember - button.btn.btn-sm.btn-warning Leave Clan + button.btn.btn-sm.btn-warning.leave-clan-btn(data-id="#{clan.id}") Leave Clan else - button.btn.btn-sm.btn-success Join Clan + button.btn.btn-sm.btn-success.join-clan-btn(data-id="#{clan.id}") Join Clan if clan.get('members') h3 Clan Members (#{clan.get('members').length}) diff --git a/app/templates/clans/clans.jade b/app/templates/clans/clans.jade index 5ce41425d..1ccd22515 100644 --- a/app/templates/clans/clans.jade +++ b/app/templates/clans/clans.jade @@ -40,7 +40,7 @@ block content if myClanIDs.indexOf(clan.id) < 0 button.btn.btn-sm.btn-success.join-clan-btn(data-id="#{clan.id}") Join Clan else if clan.get('ownerID') !== me.id - button.btn.btn-sm.btn-warning Leave Clan + button.btn.btn-sm.btn-warning.leave-clan-btn(data-id="#{clan.id}") Leave Clan button.btn.btn-sm Load More @@ -66,6 +66,6 @@ block content a(href="/user/#{clan.ownerID}")= clan.get('ownerName') td if clan.get('ownerID') !== me.id - button.btn.btn-sm.btn-warning Leave Clan + button.btn.btn-sm.btn-warning.leave-clan-btn(data-id="#{clan.id}") Leave Clan button.btn.btn-sm Load More diff --git a/app/views/clans/ClanDetailsView.coffee b/app/views/clans/ClanDetailsView.coffee index d17039664..1f507a3d9 100644 --- a/app/views/clans/ClanDetailsView.coffee +++ b/app/views/clans/ClanDetailsView.coffee @@ -1,11 +1,20 @@ +app = require 'core/application' +AuthModal = require 'views/core/AuthModal' RootView = require 'views/core/RootView' template = require 'templates/clans/clan-details' Clan = require 'models/Clan' +# TODO: join/leave mostly duped from clans view +# TODO: Refresh data instead of page + module.exports = class ClanDetailsView extends RootView id: 'clan-details-view' template: template + events: + 'click .join-clan-btn': 'onJoinClan' + 'click .leave-clan-btn': 'onLeaveClan' + constructor: (options, @clanID) -> super options @clan = new Clan _id: @clanID @@ -17,3 +26,30 @@ module.exports = class ClanDetailsView extends RootView context.isOwner = @clan.get('ownerID') is me.id context.isMember = _.find(@clan.get('members'), (m) -> m.id is me.id) ? false context + + onJoinClan: (e) -> + return @openModalView(new AuthModal()) if me.isAnonymous() + if clanID = $(e.target).data('id') + options = + url: "/db/clan/#{clanID}/join" + method: 'PUT' + error: (model, response, options) => + console.error 'Error joining clan', response + success: (model, response, options) => + window.location.reload() + @supermodel.addRequestResource( 'join_clan', options).load() + else + console.error "No clan ID attached to join button." + + onLeaveClan: (e) -> + if clanID = $(e.target).data('id') + options = + url: "/db/clan/#{clanID}/leave" + method: 'PUT' + error: (model, response, options) => + console.error 'Error leaving clan', response + success: (model, response, options) => + window.location.reload() + @supermodel.addRequestResource( 'leave_clan', options).load() + else + console.error "No clan ID attached to leave button." diff --git a/app/views/clans/ClansView.coffee b/app/views/clans/ClansView.coffee index 8abd06c48..319bf587a 100644 --- a/app/views/clans/ClansView.coffee +++ b/app/views/clans/ClansView.coffee @@ -5,6 +5,10 @@ template = require 'templates/clans/clans' CocoCollection = require 'collections/CocoCollection' Clan = require 'models/Clan' +# TODO: Waiting for async messages +# TODO: Invalid clan name message +# TODO: Refresh data instead of page + module.exports = class MainAdminView extends RootView id: 'clans-view' template: template @@ -12,6 +16,7 @@ module.exports = class MainAdminView extends RootView events: 'click .create-clan-btn': 'onClickCreateClan' 'click .join-clan-btn': 'onJoinClan' + 'click .leave-clan-btn': 'onLeaveClan' constructor: (options) -> super options @@ -30,7 +35,6 @@ module.exports = class MainAdminView extends RootView onClickCreateClan: (e) -> return @openModalView(new AuthModal()) if me.isAnonymous() if name = $('.create-clan-name').val() - # TODO: async creating message clan = new Clan() clan.set 'type', 'public' clan.set 'name', name @@ -41,7 +45,6 @@ module.exports = class MainAdminView extends RootView app.router.navigate "/clans/#{model.id}" window.location.reload() else - # TODO: Invalid name message console.log 'Invalid name' onJoinClan: (e) -> @@ -53,8 +56,21 @@ module.exports = class MainAdminView extends RootView error: (model, response, options) => console.error 'Error joining clan', response success: (model, response, options) => - console.log 'Joined clan', clanID - @render() + app.router.navigate "/clans/#{clanID}" + window.location.reload() @supermodel.addRequestResource( 'join_clan', options).load() else console.error "No clan ID attached to join button." + + onLeaveClan: (e) -> + if clanID = $(e.target).data('id') + options = + url: "/db/clan/#{clanID}/leave" + method: 'PUT' + error: (model, response, options) => + console.error 'Error leaving clan', response + success: (model, response, options) => + window.location.reload() + @supermodel.addRequestResource( 'leave_clan', options).load() + else + console.error "No clan ID attached to leave button." diff --git a/server/clans/clan_handler.coffee b/server/clans/clan_handler.coffee index 0cebf6369..f04946bd5 100644 --- a/server/clans/clan_handler.coffee +++ b/server/clans/clan_handler.coffee @@ -31,6 +31,7 @@ ClanHandler = class ClanHandler extends Handler getByRelationship: (req, res, args...) -> return @joinClan(req, res, args[0]) if args[1] is 'join' + return @leaveClan(req, res, args[0]) if args[1] is 'leave' super(arguments...) joinClan: (req, res, clanID) -> @@ -45,4 +46,13 @@ ClanHandler = class ClanHandler extends Handler return @sendDatabaseError(res, err) if err @sendSuccess(res) + leaveClan: (req, res, clanID) -> + return @sendForbiddenError(res) unless req.user? and not req.user.isAnonymous() + Clan.findById clanID, (err, clan) => + return @sendDatabaseError(res, err) if err + return @sendForbiddenError(res) if clan.get('ownerID')?.equals req.user._id + Clan.update {_id: clanID}, {$pull: {members: {id: req.user._id}}}, (err) => + return @sendDatabaseError(res, err) if err + @sendSuccess(res) + module.exports = new ClanHandler() diff --git a/test/server/functional/clan.spec.coffee b/test/server/functional/clan.spec.coffee index 993501573..8e7499c3a 100644 --- a/test/server/functional/clan.spec.coffee +++ b/test/server/functional/clan.spec.coffee @@ -128,3 +128,38 @@ describe 'Clans', -> expect(err).toBeNull() expect(res.statusCode).toBe(200) done() + + it 'Leave clan', (done) -> + loginNewUser (user1) -> + createClan 'public', (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + request.put {uri: "#{clanURL}/#{clan1.id}/leave" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + Clan.findById clan1.id, (err, clan1) -> + expect(err).toBeNull() + expect(_.find clan1.get('members'), (m) -> m.id.equals user2.id).toBeUndefined() + done() + + it 'Leave clan not member 200', (done) -> + loginNewUser (user1) -> + createClan 'public', (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/leave" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + Clan.findById clan1.id, (err, clan1) -> + expect(err).toBeNull() + expect(_.find clan1.get('members'), (m) -> m.id.equals user2.id).toBeUndefined() + done() + + it 'Leave owned clan 403', (done) -> + loginNewUser (user1) -> + createClan 'public', (clan1) -> + request.put {uri: "#{clanURL}/#{clan1.id}/leave" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(403) + done()