diff --git a/app/templates/clans/clan-details.jade b/app/templates/clans/clan-details.jade index 8a8a95bfc..2e4f62e29 100644 --- a/app/templates/clans/clan-details.jade +++ b/app/templates/clans/clan-details.jade @@ -23,7 +23,7 @@ block content td= stats.averageLevel if stats.totalAchievements tr - td Achievements + td Total Achievements td= stats.totalAchievements p @@ -47,6 +47,7 @@ block content th Name th Level th Achievements + th Favorite Language th tbody each member in members @@ -57,6 +58,9 @@ block content td if memberAchievementsMap && memberAchievementsMap[member.id] | #{memberAchievementsMap[member.id].length} + td + if memberLanguageMap && memberLanguageMap[member.id] + | #{memberLanguageMap[member.id]} td if isOwner && member.id !== clan.get('ownerID') button.btn.btn-sm.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero diff --git a/app/views/clans/ClanDetailsView.coffee b/app/views/clans/ClanDetailsView.coffee index 63423de5f..02fef00a9 100644 --- a/app/views/clans/ClanDetailsView.coffee +++ b/app/views/clans/ClanDetailsView.coffee @@ -5,6 +5,7 @@ template = require 'templates/clans/clan-details' CocoCollection = require 'collections/CocoCollection' Clan = require 'models/Clan' EarnedAchievement = require 'models/EarnedAchievement' +LevelSession = require 'models/LevelSession' User = require 'models/User' # TODO: Message for clan not found @@ -36,6 +37,7 @@ module.exports = class ClanDetailsView extends RootView context.joinClanLink = "http://localhost:3000/clans/#{@clanID}" context.owner = @owner context.memberAchievementsMap = @memberAchievementsMap + context.memberLanguageMap = @memberLanguageMap context.members = @members?.models context.isOwner = @clan.get('ownerID') is me.id context.isMember = @clanID in (me.get('clans') ? []) @@ -46,37 +48,65 @@ module.exports = class ClanDetailsView extends RootView @stats = {} @clan = new Clan _id: @clanID - @listenTo @clan, 'sync', => @render?() - @listenToOnce @clan, 'sync', => - @owner = new User _id: @clan.get('ownerID') - @listenTo @owner, 'sync', => @render?() - @supermodel.loadModel @owner, 'owner', cache: false - @supermodel.loadModel @clan, 'clan', cache: false - @members = new CocoCollection([], { url: "/db/clan/#{@clanID}/members", model: User, comparator:'slug' }) - @listenTo @members, 'sync', => - @stats.averageLevel = Math.round(@members.reduce(((sum, member) -> sum + member.level()), 0) / @members.length) - @render?() - @supermodel.loadCollection(@members, 'members', {cache: false}) - @memberAchievements = new CocoCollection([], { url: "/db/clan/#{@clanID}/member_achievements", model: EarnedAchievement, comparator:'_id' }) - @listenTo @memberAchievements, 'sync', => - @stats.totalAchievements = @memberAchievements.models.length - @memberAchievementsMap = {} - for achievement in @memberAchievements.models - user = achievement.get('user') - @memberAchievementsMap[user] ?= [] - @memberAchievementsMap[user].push achievement - @render?() - @supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false}) + @memberSessions = new CocoCollection([], { url: "/db/clan/#{@clanID}/member_sessions", model: LevelSession, comparator:'_id' }) @listenTo me, 'sync', => @render?() + @listenTo @clan, 'sync', @onClanSync + @listenTo @members, 'sync', @onMembersSync + @listenTo @memberAchievements, 'sync', @onMemberAchievementsSync + @listenTo @memberSessions, 'sync', @onMemberSessionsSync + + @supermodel.loadModel @clan, 'clan', cache: false + @supermodel.loadCollection(@members, 'members', {cache: false}) + @supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false}) + @supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false}) refreshData: -> me.fetch cache: false @members.fetch cache: false @memberAchievements.fetch cache: false + onClanSync: -> + unless @owner? + @owner = new User _id: @clan.get('ownerID') + @listenTo @owner, 'sync', => @render?() + @supermodel.loadModel @owner, 'owner', cache: false + @render?() + + onMembersSync: -> + @stats.averageLevel = Math.round(@members.reduce(((sum, member) -> sum + member.level()), 0) / @members.length) + @render?() + + onMemberAchievementsSync: -> + @stats.totalAchievements = @memberAchievements.models.length + @memberAchievementsMap = {} + for achievement in @memberAchievements.models + user = achievement.get('user') + @memberAchievementsMap[user] ?= [] + @memberAchievementsMap[user].push achievement + @render?() + + onMemberSessionsSync: -> + @memberSessionMap = {} + for levelSession in @memberSessions.models + user = levelSession.get('creator') + @memberSessionMap[user] ?= [] + @memberSessionMap[user].push levelSession + @memberLanguageMap = {} + for user of @memberSessionMap + languageCounts = {} + for levelSession in @memberSessionMap[user] + language = levelSession.get('codeLanguage') or levelSession.get('submittedCodeLanguage') + languageCounts[language] = (languageCounts[language] or 0) + 1 if language + mostUsedCount = 0 + for language, count of languageCounts + if count > mostUsedCount + mostUsedCount = count + @memberLanguageMap[user] = language + @render?() + onDeleteClan: (e) -> return @openModalView(new AuthModal()) if me.isAnonymous() options = diff --git a/server/clans/clan_handler.coffee b/server/clans/clan_handler.coffee index 61603a80d..930e6f979 100644 --- a/server/clans/clan_handler.coffee +++ b/server/clans/clan_handler.coffee @@ -3,6 +3,9 @@ mongoose = require 'mongoose' Handler = require '../commons/Handler' 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' @@ -48,6 +51,7 @@ ClanHandler = class ClanHandler extends Handler 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...) @@ -82,28 +86,39 @@ ClanHandler = class ClanHandler extends Handler getMemberAchievements: (req, res, clanID) -> # TODO: add tests - Clan.findById clanID, (err, clans) => + Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - return @sendDatabaseError(res, err) unless clans - memberIDs = _.map clans.get('members') ? [], (memberID) -> memberID.toHexString() + return @sendDatabaseError(res, err) unless clan + memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString() EarnedAchievement.find {user: {$in: memberIDs}}, (err, documents) => return @sendDatabaseError(res, err) if err? - cleandocs = (@formatEntity(req, doc) for doc in documents) + cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents) @sendSuccess(res, cleandocs) getMembers: (req, res, clanID) -> # TODO: add tests return @sendForbiddenError(res) unless req.user? and not req.user.isAnonymous() clanIDs = req.user.get('clans') ? [] - Clan.findById clanID, (err, clans) => + Clan.findById clanID, (err, clan) => return @sendDatabaseError(res, err) if err - return @sendDatabaseError(res, err) unless clans - memberIDs = clans.get('members') ? [] + return @sendDatabaseError(res, err) unless clan + memberIDs = clan.get('members') ? [] User.find {_id: {$in: memberIDs}}, (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 + 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() + LevelSession.find {creator: {$in: memberIDs}}, (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'} }]