mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-01 03:16:56 -05:00
fcf0bc85fe
Hoist memberLimit variable Don't sort member's on the server side, let the client handle it Use mongo limits instead of breaking server side.
172 lines
8.3 KiB
CoffeeScript
172 lines
8.3 KiB
CoffeeScript
async = require 'async'
|
|
mongoose = require 'mongoose'
|
|
Handler = require '../commons/Handler'
|
|
AnalyticsLogEvent = require '../analytics/AnalyticsLogEvent'
|
|
Clan = require './Clan'
|
|
EarnedAchievement = require '../achievements/EarnedAchievement'
|
|
EarnedAchievementHandler = require '../achievements/earned_achievement_handler'
|
|
LevelSession = require '../levels/sessions/LevelSession'
|
|
LevelSessionHandler = require '../levels/sessions/level_session_handler'
|
|
User = require '../users/User'
|
|
UserHandler = require '../users/user_handler'
|
|
|
|
memberLimit = 200
|
|
|
|
ClanHandler = class ClanHandler extends Handler
|
|
modelClass: Clan
|
|
jsonSchema: require '../../app/schemas/models/clan.schema'
|
|
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE']
|
|
|
|
hasAccess: (req) ->
|
|
return true if req.method is 'GET'
|
|
return false if req.method is 'POST' and req.body?.type is 'private' and not req.user?.isPremium()
|
|
req.method in @allowedMethods or req.user?.isAdmin()
|
|
|
|
hasAccessToDocument: (req, document, method=null) ->
|
|
return false unless document?
|
|
return true if req.user?.isAdmin()
|
|
return true if (method or req.method).toLowerCase() is 'get'
|
|
return true if document.get('ownerID')?.equals req.user?._id
|
|
false
|
|
|
|
makeNewInstance: (req) ->
|
|
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) ->
|
|
@getDocumentForIdOrSlug clanID, (err, clan) =>
|
|
return @sendDatabaseError res, err if err
|
|
return @sendNotFoundError res unless clan
|
|
return @sendForbiddenError res unless @hasAccessToDocument(req, clan)
|
|
memberIDs = clan.get('members')
|
|
Clan.remove {_id: clan.get('_id')}, (err) =>
|
|
return @sendDatabaseError res, err if err
|
|
User.update {_id: {$in: memberIDs}}, {$pull: {clans: clan.get('_id')}}, {multi: true}, (err) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
@sendNoContent(res)
|
|
AnalyticsLogEvent.logEvent req.user, 'Clan deleted', clanID: clanID, type: clan.get('type')
|
|
|
|
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'
|
|
return @getMemberAchievements(req, res, args[0]) if args[1] is 'member_achievements'
|
|
return @getMembers(req, res, args[0]) if args[1] is 'members'
|
|
return @getMemberSessions(req, res, args[0]) if args[1] is 'member_sessions'
|
|
return @getPublicClans(req, res) if args[1] is 'public'
|
|
return @removeMember(req, res, args[0], args[2]) if args.length is 3 and args[1] is 'remove'
|
|
super(arguments...)
|
|
|
|
joinClan: (req, res, clanID) ->
|
|
return @sendForbiddenError(res) unless req.user? and not req.user.isAnonymous()
|
|
try
|
|
clanID = mongoose.Types.ObjectId(clanID)
|
|
catch err
|
|
return @sendNotFoundError(res, err)
|
|
Clan.findById clanID, (err, clan) =>
|
|
return @sendDatabaseError(res, err) if 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
|
|
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()
|
|
try
|
|
clanID = mongoose.Types.ObjectId(clanID)
|
|
catch err
|
|
return @sendNotFoundError(res, err)
|
|
Clan.findById clanID, (err, clan) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
return @sendNotFoundError(res) unless clan
|
|
return @sendForbiddenError(res) if clan.get('ownerID')?.equals req.user._id
|
|
Clan.update {_id: clanID}, {$pull: {members: req.user._id}}, (err) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
User.update {_id: req.user._id}, {$pull: {clans: clanID}}, (err) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
@sendSuccess(res)
|
|
AnalyticsLogEvent.logEvent req.user, 'Clan left', clanID: clanID, type: clan.get('type')
|
|
|
|
getMemberAchievements: (req, res, clanID) ->
|
|
# TODO: add tests
|
|
Clan.findById clanID, (err, clan) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
return @sendNotFoundError(res) unless clan
|
|
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
|
|
User.find {_id: {$in: memberIDs}}, 'nameLower', {limit: memberLimit}, (err, users) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
memberIDs = []
|
|
for user in users
|
|
memberIDs.push user.id
|
|
EarnedAchievement.find {user: {$in: memberIDs}}, 'achievementName user', (err, documents) =>
|
|
return @sendDatabaseError(res, err) if err?
|
|
cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents)
|
|
@sendSuccess(res, cleandocs)
|
|
|
|
getMembers: (req, res, clanID) ->
|
|
# TODO: add tests
|
|
Clan.findById clanID, (err, clan) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
return @sendNotFoundError(res) unless clan
|
|
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
|
|
User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {}, (err, users) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
cleandocs = (UserHandler.formatEntity(req, doc) for doc in users)
|
|
@sendSuccess(res, cleandocs)
|
|
|
|
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 @sendNotFoundError(res) unless clan
|
|
return @sendForbiddenError(res) unless clan.get('dashboardType') is 'premium'
|
|
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
|
|
User.find {_id: {$in: memberIDs}}, 'name', {limit: memberLimit}, (err, users) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
memberIDs = []
|
|
for user in users
|
|
memberIDs.push user.id
|
|
break unless memberIDs.length < memberLimit
|
|
LevelSession.find {creator: {$in: memberIDs}}, 'changed codeLanguage creator creatorName levelID levelName playtime state submittedCodeLanguage', (err, documents) =>
|
|
return @sendDatabaseError(res, err) if err?
|
|
cleandocs = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)
|
|
@sendSuccess(res, cleandocs)
|
|
|
|
getPublicClans: (req, res) ->
|
|
# Return 100 public clans, sorted by member count, created date
|
|
query = [{ $match : {type : 'public'} }]
|
|
query.push {$project : {_id: 1, name: 1, slug: 1, type: 1, description: 1, memberCount: {$size: "$members"}, ownerID: 1}}
|
|
query.push {$sort: { memberCount: -1, _id: -1 }}
|
|
query.push {$limit: 100}
|
|
Clan.aggregate(query).exec (err, documents) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
@sendSuccess(res, documents)
|
|
|
|
removeMember: (req, res, clanID, memberID) ->
|
|
return @sendForbiddenError(res) unless req.user? and not req.user.isAnonymous()
|
|
try
|
|
clanID = mongoose.Types.ObjectId(clanID)
|
|
memberID = mongoose.Types.ObjectId(memberID)
|
|
catch err
|
|
return @sendNotFoundError(res, err)
|
|
Clan.findById clanID, (err, clan) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
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) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
User.update {_id: memberID}, {$pull: {clans: clanID}}, (err) =>
|
|
return @sendDatabaseError(res, err) if err
|
|
@sendSuccess(res)
|
|
AnalyticsLogEvent.logEvent req.user, 'Clan member removed', clanID: clanID, type: clan.get('type'), memberID: memberID
|
|
|
|
module.exports = new ClanHandler()
|