diff --git a/app/assets/images/pages/clans/dashboard_preview.png b/app/assets/images/pages/clans/dashboard_preview.png new file mode 100644 index 000000000..bfe7f2bce Binary files /dev/null and b/app/assets/images/pages/clans/dashboard_preview.png differ diff --git a/app/schemas/models/clan.schema.coffee b/app/schemas/models/clan.schema.coffee index a7d646821..acdc17cd9 100644 --- a/app/schemas/models/clan.schema.coffee +++ b/app/schemas/models/clan.schema.coffee @@ -1,5 +1,7 @@ c = require './../schemas' +# TODO: Require name to be non-empty + ClanSchema = c.object {title: 'Clan', required: ['name', 'type']} c.extendNamedProperties ClanSchema # name first @@ -7,7 +9,8 @@ _.extend ClanSchema.properties, description: {type: 'string'} members: c.array {title: 'Members'}, c.objectId() ownerID: c.objectId() - type: {type: 'string', 'enum': ['public']} + type: {type: 'string', 'enum': ['public', 'private'], description: 'Controls clan general visibility.'} + dashboardType: {type: 'string', 'enum': ['basic', 'premium']} c.extendBasicProperties ClanSchema, 'Clan' diff --git a/app/styles/clans/clan-details.sass b/app/styles/clans/clan-details.sass index 42e29f123..fc50e7559 100644 --- a/app/styles/clans/clan-details.sass +++ b/app/styles/clans/clan-details.sass @@ -10,11 +10,54 @@ width: 240px background: rgba(0, 0, 0, 0.0) + #editDescriptionModal .modal-dialog + background-color: white + + #editNameModal .modal-dialog + background-color: white + max-width: 400px + + .edit-description-input + width: 100% + + .edit-name-input + width: 100% + $spriteSheetSize: 30px - td.hero-icon-cell + + .remove-hero-cell + width: 100px + + .hero-icon-cell width: 30px + .level-cell + width: 50px + text-align: center + + .name-cell + width: 100px + + .level-progression-cell + background-color: lightblue + border: 1px solid gray + // cursor: pointer + padding: 4px + + .level-popup-container + display: none + position: absolute + padding: 10px + border: 1px solid black + z-index: 3 + background-color: blanchedalmond + font-size: 10pt + + .level-progression-cell-name + background-color: lightblue + border: 1px solid gray + .player-hero-icon background: transparent url(/images/pages/play/play-spritesheet.png) background-size: cover diff --git a/app/styles/clans/clans.sass b/app/styles/clans/clans.sass index 55e7d501d..2ae06af77 100644 --- a/app/styles/clans/clans.sass +++ b/app/styles/clans/clans.sass @@ -6,3 +6,6 @@ .create-clan-description width: 50% + + .popover + max-width: 100% diff --git a/app/templates/clans/clan-details.jade b/app/templates/clans/clan-details.jade index a23a67b96..545a16e31 100644 --- a/app/templates/clans/clan-details.jade +++ b/app/templates/clans/clan-details.jade @@ -2,12 +2,44 @@ extends /templates/base block content + .modal#editNameModal + .modal-dialog + .modal-header + button.close(data-dismiss='modal') + span × + h3.modal-title Edit Clan Name + .modal-body + input.edit-name-input(type='text' value="#{clan.get('name')}") + .modal-footer + button.btn(data-dismiss='modal') Close + button.btn.edit-name-save-btn Save changes + + .modal#editDescriptionModal + .modal-dialog + .modal-header + button.close(data-dismiss='modal') + span × + h3.modal-title Edit Clan Description + .modal-body + textarea.edit-description-input(rows=2)= clan.get('description') + .modal-footer + button.btn(data-dismiss='modal') Close + button.btn.edit-description-save-btn Save changes + if clan - h1= clan.get('name') + h1 #{clan.get('name')} + if clan.get('type') === 'private' + small (private) + if clan.get('ownerID') === me.id + span.spl + button.btn.btn-xs.edit-name-btn(data-toggle='modal', data-target='#editNameModal') edit name + if clan.get('description') .clan-description each line in clan.get('description').split('\n') p= line + if clan.get('ownerID') === me.id + button.btn.btn-xs.edit-description-btn(data-toggle='modal', data-target='#editDescriptionModal') edit description h5 Summary table.table.table-condensed.stats-table @@ -22,7 +54,7 @@ block content tr td Average Level td= stats.averageLevel - if stats.totalAchievements + if stats.totalAchievements && clan.get('type') === 'public' tr td Total Achievements td= stats.totalAchievements @@ -35,40 +67,78 @@ block content else button.btn.btn-lg.btn-success.join-clan-btn Join Clan - div - span.spl.spr.join-link-prompt Invite: - input.join-clan-link(type="text", readonly, value="#{joinClanLink}") - .small *Invite players to this Clan by sending them this link. + if clan.get('ownerID') === me.id || clan.get('type') === 'public' + div + span.spl.spr.join-link-prompt Invite: + input.join-clan-link(type="text", readonly, value="#{joinClanLink}") + .small *Invite players to this Clan by sending them this link. if members h3 Heroes (#{members.length}) - table.table.table-striped.table-condensed - thead - tr - th - th - td Name - th Level - th Achievements - th Latest Achievement - th - tbody - each member in members + if clan.get('dashboardType') === 'premium' + table.table.table-condensed + thead tr - td.hero-icon-cell - span.spr.player-hero-icon(data-memberid="#{member.id}") - td.code-language-cell - if memberLanguageMap && memberLanguageMap[member.id] - span.code-language-cell(style="background-image: url(/images/common/code_languages/#{memberLanguageMap[member.id]}_small.png)", title=memberLanguageMap[member.id]) - td - a(href="/user/#{member.id}")= member.get('name') || 'Anoner' - td= member.level() - td - if memberAchievementsMap && memberAchievementsMap[member.id] - | #{memberAchievementsMap[member.id].length} - td - if memberAchievementsMap && memberAchievementsMap[member.id] && memberAchievementsMap[member.id].length - span= memberAchievementsMap[member.id][0].get('achievementName') - td - if isOwner && member.id !== clan.get('ownerID') - button.btn.btn-xs.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero + if isOwner + th + th + th + th Level + th Name + th(colspan="#{memberMaxLevelCount + 1}") Last Level Completed + tbody + each member in members + tr + if isOwner + td.remove-hero-cell + if member.id !== clan.get('ownerID') + button.btn.btn-xs.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero + td.hero-icon-cell + span.spr.player-hero-icon(data-memberid="#{member.id}") + td.code-language-cell + if memberLanguageMap && memberLanguageMap[member.id] + span.code-language-cell(style="background-image: url(/images/common/code_languages/#{memberLanguageMap[member.id]}_small.png)", title=memberLanguageMap[member.id]) + td.level-cell= member.level() + td.name-cell + a(href="/user/#{member.id}")= member.get('name') || 'Anoner' + if memberLevelProgression && memberLevelProgression[member.id] + each levelInfo in memberLevelProgression[member.id] + td.level-progression-cell + .level-popup-container + div Level: #{levelInfo.level} + div Playtime: #{levelInfo.playtime} + div Last played: #{levelInfo.changed} + td(colspan="#{memberMaxLevelCount - memberLevelProgression[member.id].length + 1}")= memberLevelProgression[member.id][memberLevelProgression[member.id].length - 1].level + else + td(colspan="#{memberMaxLevelCount + 1}") + else + table.table.table-striped.table-condensed + thead + tr + th + th + td Name + th Level + th Achievements + th Latest Achievement + th + tbody + each member in members + tr + td.hero-icon-cell + span.spr.player-hero-icon(data-memberid="#{member.id}") + td.code-language-cell + if memberLanguageMap && memberLanguageMap[member.id] + span.code-language-cell(style="background-image: url(/images/common/code_languages/#{memberLanguageMap[member.id]}_small.png)", title=memberLanguageMap[member.id]) + td + a(href="/user/#{member.id}")= member.get('name') || 'Anoner' + td= member.level() + td + if memberAchievementsMap && memberAchievementsMap[member.id] + | #{memberAchievementsMap[member.id].length} + td + if memberAchievementsMap && memberAchievementsMap[member.id] && memberAchievementsMap[member.id].length + span= memberAchievementsMap[member.id][0].get('achievementName') + td + if isOwner && member.id !== clan.get('ownerID') + button.btn.btn-xs.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero diff --git a/app/templates/clans/clans.jade b/app/templates/clans/clans.jade index 5d87b4960..3ba399c56 100644 --- a/app/templates/clans/clans.jade +++ b/app/templates/clans/clans.jade @@ -6,6 +6,12 @@ block content input.create-clan-name(type='text' placeholder='New clan name') p textarea.create-clan-description(rows=2, placeholder='New clan description') + p + input(type='checkbox').private-clan-checkbox + span.spl Private + span.spl ( + a.private-more-info more info + span ) p button.btn.btn-success.create-clan-btn Create New Clan @@ -53,6 +59,7 @@ block content th Clan Name th Heroes th Chieftain + th Type th tbody if myClans.length @@ -69,6 +76,7 @@ block content a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')] else a(href="/user/#{clan.get('ownerID')}") Anoner + td= clan.get('type') td if clan.get('ownerID') !== me.id button.btn.btn-xs.btn-warning.leave-clan-btn(data-id="#{clan.id}") Leave Clan diff --git a/app/views/clans/ClanDetailsView.coffee b/app/views/clans/ClanDetailsView.coffee index 337e4c490..70d89a105 100644 --- a/app/views/clans/ClanDetailsView.coffee +++ b/app/views/clans/ClanDetailsView.coffee @@ -1,15 +1,16 @@ -app = require 'core/application' -AuthModal = require 'views/core/AuthModal' RootView = require 'views/core/RootView' template = require 'templates/clans/clan-details' +app = require 'core/application' +AuthModal = require 'views/core/AuthModal' CocoCollection = require 'collections/CocoCollection' Clan = require 'models/Clan' EarnedAchievement = require 'models/EarnedAchievement' LevelSession = require 'models/LevelSession' +SubscribeModal = require 'views/core/SubscribeModal' ThangType = require 'models/ThangType' User = require 'models/User' -# TODO: Message for clan not found +# TODO: Add message for clan not found # TODO: join/leave mostly duped from clans view module.exports = class ClanDetailsView extends RootView @@ -18,9 +19,13 @@ module.exports = class ClanDetailsView extends RootView events: 'click .delete-clan-btn': 'onDeleteClan' + 'click .edit-description-save-btn': 'onEditDescriptionSave' + 'click .edit-name-save-btn': 'onEditNameSave' 'click .join-clan-btn': 'onJoinClan' 'click .leave-clan-btn': 'onLeaveClan' 'click .remove-member-btn': 'onRemoveMember' + 'mouseenter .level-progression-cell': 'onMouseEnterPoint' + 'mouseleave .level-progression-cell': 'onMouseLeavePoint' constructor: (options, @clanID) -> super options @@ -59,6 +64,8 @@ module.exports = class ClanDetailsView extends RootView context.owner = @owner context.memberAchievementsMap = @memberAchievementsMap context.memberLanguageMap = @memberLanguageMap + context.memberLevelProgression = @memberLevelProgression + context.memberMaxLevelCount = @memberMaxLevelCount context.members = @members?.models context.isOwner = @clan.get('ownerID') is me.id context.isMember = @clanID in (me.get('clans') ? []) @@ -73,6 +80,7 @@ module.exports = class ClanDetailsView extends RootView me.fetch cache: false @members.fetch cache: false @memberAchievements.fetch cache: false + @memberSessions.fetch cache: false updateHeroIcons: -> return unless @members?.models? @@ -104,17 +112,27 @@ module.exports = class ClanDetailsView extends RootView @render?() onMemberSessionsSync: -> - @memberSessionMap = {} + @memberLevelProgression = {} + memberSessions = {} for levelSession in @memberSessions.models user = levelSession.get('creator') - @memberSessionMap[user] ?= [] - @memberSessionMap[user].push levelSession + if not levelSession.isMultiplayer() and levelSession.get('state')?.complete is true + memberSessions[user] ?= [] + memberSessions[user].push levelSession + @memberLevelProgression[user] ?= [] + levelInfo = + level: levelSession.get('levelName') + changed: new Date(levelSession.get('changed')).toLocaleString() + playtime: levelSession.get('playtime') + @memberLevelProgression[user].push levelInfo + @memberMaxLevelCount = 0 @memberLanguageMap = {} - for user of @memberSessionMap + for user of memberSessions languageCounts = {} - for levelSession in @memberSessionMap[user] + for levelSession in memberSessions[user] language = levelSession.get('codeLanguage') or levelSession.get('submittedCodeLanguage') languageCounts[language] = (languageCounts[language] or 0) + 1 if language + @memberMaxLevelCount = memberSessions[user].length if @memberMaxLevelCount < memberSessions[user].length mostUsedCount = 0 for language, count of languageCounts if count > mostUsedCount @@ -122,6 +140,18 @@ module.exports = class ClanDetailsView extends RootView @memberLanguageMap[user] = language @render?() + onMouseEnterPoint: (e) -> + container = $(e.target).find('.level-popup-container').show() + margin = 20 + offset = $(e.target).offset() + scrollTop = $(e.target).offsetParent().scrollTop() + height = container.outerHeight() + container.css('left', offset.left + e.offsetX) + container.css('top', offset.top + scrollTop - height - margin) + + onMouseLeavePoint: (e) -> + $(e.target).find('.level-popup-container').hide() + onDeleteClan: (e) -> return @openModalView(new AuthModal()) if me.isAnonymous() options = @@ -134,8 +164,25 @@ module.exports = class ClanDetailsView extends RootView window.location.reload() @supermodel.addRequestResource( 'delete_clan', options).load() + onEditDescriptionSave: (e) -> + description = $('.edit-description-input').val() + @clan.set 'description', description + @clan.patch() + $('#editDescriptionModal').modal('hide') + + onEditNameSave: (e) -> + if name = $('.edit-name-input').val() + @clan.set 'name', name + @clan.patch() + $('#editNameModal').modal('hide') + onJoinClan: (e) -> return @openModalView(new AuthModal()) if me.isAnonymous() + return unless @clan.loaded + if @clan.get('type') is 'private' and not me.isPremium() + @openModalView new SubscribeModal() + window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'join clan' + return options = url: "/db/clan/#{@clanID}/join" method: 'PUT' diff --git a/app/views/clans/ClansView.coffee b/app/views/clans/ClansView.coffee index 5936ead1f..79348e7e5 100644 --- a/app/views/clans/ClansView.coffee +++ b/app/views/clans/ClansView.coffee @@ -4,6 +4,7 @@ RootView = require 'views/core/RootView' template = require 'templates/clans/clans' CocoCollection = require 'collections/CocoCollection' Clan = require 'models/Clan' +SubscribeModal = require 'views/core/SubscribeModal' # TODO: Waiting for async messages # TODO: Invalid clan name message @@ -28,11 +29,15 @@ module.exports = class MainAdminView extends RootView getRenderData: -> context = super() context.idNameMap = @idNameMap - context.publicClans = @publicClans.models + context.publicClans = _.filter(@publicClans.models, (clan) -> clan.get('type') is 'public') context.myClans = @myClans.models context.myClanIDs = me.get('clans') ? [] context + afterRender: -> + super() + @setupPrivateInfoPopover() + initData: -> @idNameMap = {} @@ -54,20 +59,47 @@ module.exports = class MainAdminView extends RootView @listenTo me, 'sync', => @render?() refreshNames: (clans) -> + clanIDs = _.filter(clans, (clan) -> clan.get('type') is 'public') + clanIDs = _.map(clans, (clan) -> clan.get('ownerID')) options = url: '/db/user/-/names' method: 'POST' - data: {ids: _.map(clans, (clan) -> clan.get('ownerID'))} + data: {ids: clanIDs} success: (models, response, options) => @idNameMap[userID] = models[userID].name for userID of models @render?() @supermodel.addRequestResource('user_names', options, 0).load() + setupPrivateInfoPopover: -> + popoverTitle = 'Private Clans' + popoverContent = "

Additional features:" + popoverContent += "

" + popoverContent += "

" + popoverContent += "

*A CodeCombat subscription is required to create or join private Clans.

" + @$el.find('.private-more-info').popover( + animation: true + html: true + placement: 'right' + trigger: 'hover' + title: popoverTitle + content: popoverContent + container: @$el + ) + onClickCreateClan: (e) -> - return @openModalView(new AuthModal()) if me.isAnonymous() + return @openModalView new AuthModal() if me.isAnonymous() + clanType = if $('.private-clan-checkbox').prop('checked') then 'private' else 'public' + if clanType is 'private' and not me.isPremium() + @openModalView new SubscribeModal() + window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'create clan' + return if name = $('.create-clan-name').val() clan = new Clan() - clan.set 'type', 'public' + clan.set 'type', clanType clan.set 'name', name clan.set 'description', description if description = $('.create-clan-description').val() clan.save {}, diff --git a/server/clans/clan_handler.coffee b/server/clans/clan_handler.coffee index a4fe13f99..15372cd02 100644 --- a/server/clans/clan_handler.coffee +++ b/server/clans/clan_handler.coffee @@ -17,13 +17,15 @@ ClanHandler = class ClanHandler extends Handler hasAccess: (req) -> return true if req.method in ['GET'] - return true if req.user? and not req.user.isAnonymous() + return false unless req.user? + return false if req.user.isAnonymous() + return true if req.body.type is 'public' or req.user.isPremium() false hasAccessToDocument: (req, document, method=null) -> return false unless document? - method = (method or req.method).toLowerCase() return true if req.user?.isAdmin() + method = (method or req.method).toLowerCase() return true if method is 'get' return true if document.get('ownerID')?.equals req.user._id false @@ -33,6 +35,7 @@ ClanHandler = class ClanHandler extends Handler instance = super(req) instance.set 'ownerID', req.user._id instance.set 'members', [req.user._id] + instance.set 'dashboardType', 'premium' if req.body?.type is 'private' instance delete: (req, res, clanID) -> @@ -64,12 +67,17 @@ ClanHandler = class ClanHandler extends Handler clanID = mongoose.Types.ObjectId(clanID) catch err return @sendNotFoundError(res, err) - Clan.update {_id: clanID}, {$addToSet: {members: req.user._id}}, (err) => + Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - User.update {_id: req.user._id}, {$addToSet: {clans: clanID}}, (err) => + return @sendNotFoundError(res) unless clan + return @sendDatabaseError(res, err) unless clanType = clan.get('type') + return @sendForbiddenError(res) unless clanType is 'public' or req.user.isPremium() + Clan.update {_id: clanID}, {$addToSet: {members: req.user._id}}, (err) => return @sendDatabaseError(res, err) if err - @sendSuccess(res) - AnalyticsLogEvent.logEvent req.user, 'Clan joined', clanID: clanID, type: 'public' + User.update {_id: req.user._id}, {$addToSet: {clans: clanID}}, (err) => + return @sendDatabaseError(res, err) if err + @sendSuccess(res) + AnalyticsLogEvent.logEvent req.user, 'Clan joined', clanID: clanID, type: clanType leaveClan: (req, res, clanID) -> return @sendForbiddenError(res) unless req.user? and not req.user.isAnonymous() @@ -92,8 +100,8 @@ ClanHandler = class ClanHandler extends Handler # TODO: add tests Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - return @sendDatabaseError(res, err) unless clan - memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString() + return @sendNotFoundError(res) unless clan + memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID EarnedAchievement.find {user: {$in: memberIDs}}, (err, documents) => return @sendDatabaseError(res, err) if err? cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents) @@ -103,7 +111,7 @@ ClanHandler = class ClanHandler extends Handler # TODO: add tests Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - return @sendDatabaseError(res, err) unless clan + return @sendNotFoundError(res) unless clan memberIDs = clan.get('members') ? [] User.find {_id: {$in: memberIDs}}, (err, users) => return @sendDatabaseError(res, err) if err @@ -112,10 +120,11 @@ ClanHandler = class ClanHandler extends Handler getMemberSessions: (req, res, clanID) -> # TODO: add tests + # TODO: restrict information returned based on clan type Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - return @sendDatabaseError(res, err) unless clan - memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString() + return @sendNotFoundError(res) unless clan + memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID LevelSession.find {creator: {$in: memberIDs}}, 'creatorName levelName codeLanguage submittedCodeLanguage', (err, documents) => return @sendDatabaseError(res, err) if err? cleandocs = (LevelSessionHandler.formatEntity(req, doc) for doc in documents) @@ -140,7 +149,7 @@ ClanHandler = class ClanHandler extends Handler return @sendNotFoundError(res, err) Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - return @sendDatabaseError(res, err) unless clan + return @sendNotFoundError(res) unless clan return @sendForbiddenError res unless @hasAccessToDocument(req, clan) return @sendForbiddenError(res) if clan.get('ownerID').equals memberID Clan.update {_id: clanID}, {$pull: {members: memberID}}, (err) => diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index 18c362c7e..d940b7354 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -543,7 +543,9 @@ UserHandler = class UserHandler extends Handler @getDocumentForIdOrSlug userIDOrSlug, (err, user) => return @sendNotFoundError(res) if not user clanIDs = user.get('clans') ? [] - Clan.find {_id: {$in: clanIDs}}, (err, documents) => + query = {$and: [{_id: {$in: clanIDs}}]} + query['$and'].push {type: 'public'} unless req.user.id is user.id + Clan.find query, (err, documents) => return @sendDatabaseError(res, err) if err @sendSuccess(res, documents) diff --git a/test/server/functional/clan.spec.coffee b/test/server/functional/clan.spec.coffee index 92f6d5522..b5bdf79df 100644 --- a/test/server/functional/clan.spec.coffee +++ b/test/server/functional/clan.spec.coffee @@ -6,6 +6,7 @@ mongoose = require 'mongoose' describe 'Clans', -> stripe = require('stripe')(config.stripe.secretKey) clanURL = getURL('/db/clan') + userURL = getURL('/db/user') clanCount = 0 createClanName = (name) -> name + clanCount++ @@ -22,12 +23,14 @@ describe 'Clans', -> expect(body.type).toEqual(type) expect(body.name).toEqual(name) expect(body.description).toEqual(description) if description? + expect(body.dashboardType).toEqual('premium') if type is 'private' expect(body.members?.length).toEqual(1) expect(body.members?[0]).toEqual(user.id) Clan.findById body._id, (err, clan) -> expect(clan.get('type')).toEqual(type) expect(clan.get('name')).toEqual(name) expect(clan.get('description')).toEqual(description) if description? + expect(clan.get('dashboardType')).toEqual('premium') if type is 'private' expect(clan.get('members')?.length).toEqual(1) expect(clan.get('members')?[0]).toEqual(user._id) User.findById user.id, (err, user) -> @@ -41,269 +44,466 @@ describe 'Clans', -> throw err if err done() - it 'Create clan', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', 'test description', (clan) -> - done() + describe 'Public', -> - it 'Anonymous create clan 401', (done) -> - logoutUser -> - requestBody = - type: 'public' - name: createClanName 'myclan' - request.post {uri: clanURL, json: requestBody }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(401) - done() + it 'Create clan', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', 'test description', (clan) -> + done() - it 'Create clan missing type 422', (done) -> - loginNewUser (user1) -> - requestBody = - name: createClanName 'myclan' - request.post {uri: clanURL, json: requestBody }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(422) - done() + it 'Anonymous create clan 401', (done) -> + logoutUser -> + requestBody = + type: 'public' + name: createClanName 'myclan' + request.post {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(401) + done() - it 'Create clan missing name 422', (done) -> - loginNewUser (user1) -> - requestBody = - type: 'public' - request.post {uri: clanURL, json: requestBody }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(422) - done() + it 'Create clan missing type 403', (done) -> + loginNewUser (user1) -> + requestBody = + name: createClanName 'myclan' + request.post {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(403) + done() - it 'Get public clans', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - createClan user1, 'public', 'the second clan', (clan2) -> - request.get {uri: "#{clanURL}/-/public" }, (err, res, body) -> + it 'Create clan missing name 422', (done) -> + loginNewUser (user1) -> + requestBody = + type: 'public' + request.post {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(422) + done() + + it 'Edit clan name', (done) -> + newName = 'new clan name' + loginNewUser (user1) -> + createClan user1, 'public', 'test description', (clan) -> + requestBody = clan.toObject() + requestBody.name = newName + request.put {uri: clanURL, json: requestBody }, (err, res, body) -> expect(err).toBeNull() - expect(res.statusCode).toBe(200) - expect(body.length).toBeGreaterThan(1) - done() + expect(body.name).toEqual(newName) + Clan.findById clan.id, (err, clan) -> + expect(err).toBeNull() + expect(clan.get('name')).toEqual(newName) + done() - it 'Get public clans anonymous', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - createClan user1, 'public', null, (clan2) -> - logoutUser -> + it 'Edit clan name, not owner 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', 'test description', (clan) -> + oldName = clan.get('name') + loginNewUser (user2) -> + requestBody = clan.toObject() + requestBody.name = 'new clan name' + request.put {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toEqual(403) + Clan.findById clan.id, (err, clan) -> + expect(err).toBeNull() + expect(clan.get('name')).toEqual(oldName) + done() + + it 'Edit clan description', (done) -> + newDescription = 'new description' + loginNewUser (user1) -> + createClan user1, 'public', 'test description', (clan) -> + requestBody = clan.toObject() + requestBody.description = newDescription + request.put {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(body.description).toEqual(newDescription) + Clan.findById clan.id, (err, clan) -> + expect(err).toBeNull() + expect(clan.get('description')).toEqual(newDescription) + done() + + it 'Edit clan description, not owner 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', 'test description', (clan) -> + oldDescription = clan.get('description') + loginNewUser (user2) -> + requestBody = clan.toObject() + requestBody.description = 'new description' + request.put {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toEqual(403) + Clan.findById clan.id, (err, clan) -> + expect(err).toBeNull() + expect(clan.get('description')).toEqual(oldDescription) + done() + + it 'Get public clans', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + createClan user1, 'public', 'the second clan', (clan2) -> request.get {uri: "#{clanURL}/-/public" }, (err, res, body) -> expect(err).toBeNull() expect(res.statusCode).toBe(200) expect(body.length).toBeGreaterThan(1) done() - it 'Join clan', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(200) - Clan.findById clan1.id, (err, clan1) -> - expect(err).toBeNull() - expect(clan1.get('members')?.length).toEqual(2) - expect(_.find clan1.get('members'), (memberID) -> user2._id.equals memberID).toBeDefined() - User.findById user2.id, (err, user2) -> - expect(err).toBeNull() - expect(user2.get('clans')?.length).toBeGreaterThan(0) - expect(_.find user2.get('clans'), (clanID) -> clan1._id.equals clanID).toBeDefined() - done() - - it 'Join invalid clan 404', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/1234/join" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(404) - done() - - it 'Join clan anonymous 401', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - logoutUser -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(401) - done() - - it 'Join clan twice 200', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (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'), (memberID) -> memberID.equals user2.id).toBeDefined() - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + it 'Get public clans anonymous', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + createClan user1, 'public', null, (clan2) -> + logoutUser -> + request.get {uri: "#{clanURL}/-/public" }, (err, res, body) -> expect(err).toBeNull() expect(res.statusCode).toBe(200) + expect(body.length).toBeGreaterThan(1) done() - it 'Leave clan', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', 'do not stay too long', (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(200) + it 'Join clan', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + Clan.findById clan1.id, (err, clan1) -> + expect(err).toBeNull() + expect(clan1.get('members')?.length).toEqual(2) + expect(_.find clan1.get('members'), (memberID) -> user2._id.equals memberID).toBeDefined() + User.findById user2.id, (err, user2) -> + expect(err).toBeNull() + expect(user2.get('clans')?.length).toBeGreaterThan(0) + expect(_.find user2.get('clans'), (clanID) -> clan1._id.equals clanID).toBeDefined() + done() + + it 'Join invalid clan 404', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/1234/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(404) + done() + + it 'Join clan anonymous 401', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + logoutUser -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(401) + done() + + it 'Join clan twice 200', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (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'), (memberID) -> memberID.equals user2.id).toBeDefined() + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + done() + + it 'Leave clan', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', 'do not stay too long', (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'), (memberID) -> memberID.equals user2.id).toBeUndefined() + User.findById user2.id, (err, user2) -> + expect(err).toBeNull() + expect(user2.get('clans').length).toEqual(0) + done() + + it 'Leave clan not member 200', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (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'), (memberID) -> memberID.equals user2.id).toBeUndefined() - User.findById user2.id, (err, user2) -> - expect(err).toBeNull() - expect(user2.get('clans').length).toEqual(0) - done() - - it 'Leave clan not member 200', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (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'), (memberID) -> memberID.equals user2.id).toBeUndefined() - done() - - it 'Leave owned clan 403', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - request.put {uri: "#{clanURL}/#{clan1.id}/leave" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(403) - done() - - it 'Remove member', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(200) - loginUser user1, (user1) -> - request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(200) - Clan.findById clan1.id, (err, clan1) -> - expect(err).toBeNull() - expect(clan1.get('members').length).toEqual(1) - expect(clan1.get('members')[0]).toEqual(user1.get('_id')) - User.findById user2.id, (err, user2) -> - expect(err).toBeNull() - expect(user2.get('clans').length).toEqual(0) - done() - - it 'Remove non-member 200', (done) -> - loginNewUser (user2) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(200) - Clan.findById clan1.id, (err, clan1) -> - expect(err).toBeNull() - expect(clan1.get('members').length).toEqual(1) - expect(clan1.get('members')[0]).toEqual(user1.get('_id')) - done() - - it 'Remove invalid memberID 404', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - request.put {uri: "#{clanURL}/#{clan1.id}/remove/123" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(404) - done() - - it 'Remove member, not in clan 403', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(200) - loginNewUser (user3) -> - request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(403) done() - it 'Remove member, not the owner 403', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - loginNewUser (user2) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + it 'Leave owned clan 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + request.put {uri: "#{clanURL}/#{clan1.id}/leave" }, (err, res, body) -> expect(err).toBeNull() - expect(res.statusCode).toBe(200) - loginNewUser (user3) -> - request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(res.statusCode).toBe(403) + done() + + it 'Remove member', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + loginUser user1, (user1) -> + request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + Clan.findById clan1.id, (err, clan1) -> + expect(err).toBeNull() + expect(clan1.get('members').length).toEqual(1) + expect(clan1.get('members')[0]).toEqual(user1.get('_id')) + User.findById user2.id, (err, user2) -> + expect(err).toBeNull() + expect(user2.get('clans').length).toEqual(0) + done() + + it 'Remove non-member 200', (done) -> + loginNewUser (user2) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + Clan.findById clan1.id, (err, clan1) -> expect(err).toBeNull() - expect(res.statusCode).toBe(200) + expect(clan1.get('members').length).toEqual(1) + expect(clan1.get('members')[0]).toEqual(user1.get('_id')) + done() + + it 'Remove invalid memberID 404', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + request.put {uri: "#{clanURL}/#{clan1.id}/remove/123" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(404) + done() + + it 'Remove member, not in clan 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + loginNewUser (user3) -> request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> expect(err).toBeNull() expect(res.statusCode).toBe(403) done() - it 'Remove member from owned clan 403', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan1) -> - request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user1.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(403) - done() + it 'Remove member, not the owner 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + loginNewUser (user2) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + loginNewUser (user3) -> + request.put {uri: "#{clanURL}/#{clan1.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user2.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(403) + done() - it 'Delete clan', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan) -> - request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(204) - User.findById user1.id, (err, user1) -> - expect(err).toBeNull() - expect(user1.get('clans').length).toEqual(0) - done() - - it 'Delete clan anonymous 401', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan) -> - logoutUser -> - request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(401) - done() - - it 'Delete clan not owner 403', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan) -> - loginNewUser (user2) -> - request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> + it 'Remove member from owned clan 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + request.put {uri: "#{clanURL}/#{clan1.id}/remove/#{user1.id}" }, (err, res, body) -> expect(err).toBeNull() expect(res.statusCode).toBe(403) done() - it 'Delete clan no longer exists 404', (done) -> - loginNewUser (user1) -> - createClan user1, 'public', null, (clan) -> - request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(204) + it 'Delete clan', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan) -> request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> expect(err).toBeNull() - expect(res.statusCode).toBe(404) + expect(res.statusCode).toBe(204) + User.findById user1.id, (err, user1) -> + expect(err).toBeNull() + expect(user1.get('clans').length).toEqual(0) + done() + + it 'Delete clan anonymous 401', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan) -> + logoutUser -> + request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(401) + done() + + it 'Delete clan not owner 403', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan) -> + loginNewUser (user2) -> + request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(403) + done() + + it 'Delete clan no longer exists 404', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan) -> + request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(204) + request.del {uri: "#{clanURL}/#{clan.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(404) + done() + + it 'Delete clan invalid ID 404', (done) -> + loginNewUser (user1) -> + request.del {uri: "#{clanURL}/1234" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(404) + done() + + describe 'Private', -> + # Using stripe.free = true to convert users to premium + + it 'Create clan', (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'test description', (clan) -> done() - it 'Delete clan invalid ID 404', (done) -> - loginNewUser (user1) -> - request.del {uri: "#{clanURL}/1234" }, (err, res, body) -> - expect(err).toBeNull() - expect(res.statusCode).toBe(404) - done() + it 'Create clan when not premium 403', (done) -> + loginNewUser (user1) -> + requestBody = + type: 'private' + name: createClanName 'myclan' + request.post {uri: clanURL, json: requestBody }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(403) + done() + + it 'Join clan', (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'test description', (clan) -> + loginNewUser (user2) -> + user2.set 'stripe.free', true + user2.save (err) -> + request.put {uri: "#{clanURL}/#{clan.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + done() + + it 'Join clan when not premium 403', (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'test description', (clan) -> + loginNewUser (user2) -> + user2.save (err) -> + request.put {uri: "#{clanURL}/#{clan.id}/join" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(403) + done() + + it 'Get public clans after creating a private clan', (done) -> + loginNewUser (user1) -> + createClan user1, 'public', null, (clan1) -> + user1.set 'stripe.free', true + user1.save (err) -> + createClan user1, 'private', 'my private clan', (clan2) -> + request.get {uri: "#{clanURL}/-/public" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + clans = JSON.parse(body) + expect(clans.length).toBeGreaterThan(1) + for clan in clans + expect(clan._id).not.toEqual(clan2.id) + done() + + it "Getting nother user's clans excludes their private ones", (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'my private clan', (clan1) -> + createClan user1, 'public', 'my public clan', (clan2) -> + loginNewUser (user2) -> + request.get {uri: "#{userURL}/#{user1.id}/clans" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + clans = JSON.parse(body) + expect(clans.length).toEqual(1) + for clan in clans + expect(clan._id).toEqual(clan2.id) + expect(clan.type).toEqual('public') + done() + + it "Getting own clans includes private ones", (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'my private clan', (clan1) -> + createClan user1, 'public', 'my public clan', (clan2) -> + request.get {uri: "#{userURL}/#{user1.id}/clans" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + clans = JSON.parse(body) + expect(clans.length).toEqual(2) + for clan in clans + if clan.type is 'public' + expect(clan._id).toEqual(clan2.id) + else + expect(clan._id).toEqual(clan1.id) + expect(clan.type).toEqual('private') + done() + + it "Can get another user's private clan", (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'my private clan', (clan1) -> + loginNewUser (user2) -> + request.get {uri: "#{clanURL}/#{clan1.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + clan = JSON.parse(body) + expect(clan._id).toEqual(clan1.id) + expect(clan.name).toEqual(clan1.get('name')) + expect(clan.type).toEqual('private') + expect(clan1.get('ownerID').equals clan.ownerID).toEqual(true) + expect(clan.description).toEqual(clan1.get('description')) + done() + + it "Can get another user's private clan as anonymous", (done) -> + loginNewUser (user1) -> + user1.set 'stripe.free', true + user1.save (err) -> + expect(err).toBeNull() + createClan user1, 'private', 'my private clan', (clan1) -> + logoutUser -> + request.get {uri: "#{clanURL}/#{clan1.id}" }, (err, res, body) -> + expect(err).toBeNull() + expect(res.statusCode).toBe(200) + clan = JSON.parse(body) + expect(clan._id).toEqual(clan1.id) + expect(clan.name).toEqual(clan1.get('name')) + expect(clan.type).toEqual('private') + expect(clan1.get('ownerID').equals clan.ownerID).toEqual(true) + expect(clan.description).toEqual(clan1.get('description')) + done()