Merge branch 'master' into production

This commit is contained in:
Nick Winter 2015-11-06 13:00:33 -08:00
commit ec38e5fc71
9 changed files with 38 additions and 51 deletions

View file

@ -259,8 +259,6 @@
victory_new_item: "New Item" victory_new_item: "New Item"
victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks." victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
victory_become_a_viking: "Become a Viking" victory_become_a_viking: "Become a Viking"
victory_bloc: "Great work! Your skills are improving, and someone's taking notice. If you've considered becoming a software developer, this may be your lucky day. Bloc is an online bootcamp that pairs you 1-on-1 with an expert mentor who will help train you into a professional developer! By beating A Mayhem of Munchkins, you're now eligible for a $500 price reduction with the code: CCRULES"
victory_bloc_cta: "Meet your mentor learn about Bloc"
guide_title: "Guide" guide_title: "Guide"
tome_minion_spells: "Your Minions' Spells" # Only in old-style levels. tome_minion_spells: "Your Minions' Spells" # Only in old-style levels.
tome_read_only_spells: "Read-Only Spells" # Only in old-style levels. tome_read_only_spells: "Read-Only Spells" # Only in old-style levels.
@ -363,7 +361,6 @@
auth_caption: "Save your progress." auth_caption: "Save your progress."
leaderboard: leaderboard:
leaderboard: "Leaderboard"
view_other_solutions: "View Leaderboards" view_other_solutions: "View Leaderboards"
scores: "Scores" scores: "Scores"
top_players: "Top Players by" top_players: "Top Players by"
@ -899,9 +896,6 @@
send_invites: "Send Invites" send_invites: "Send Invites"
title: "Title" title: "Title"
description: "Description" description: "Description"
languages_available: "Select programming languages available to the class:"
all_lang: "All Languages"
show_progress: "Show student progress to everyone in the class"
creating_class: "Creating class..." creating_class: "Creating class..."
purchasing_course: "Purchasing course..." purchasing_course: "Purchasing course..."
buy_course: "Buy Course" buy_course: "Buy Course"
@ -1216,12 +1210,6 @@
last_earned: "Last Earned" last_earned: "Last Earned"
amount_achieved: "Amount" amount_achieved: "Amount"
achievement: "Achievement" achievement: "Achievement"
category_contributor: "Contributor"
category_ladder: "Ladder"
category_level: "Level"
category_miscellaneous: "Miscellaneous"
category_levels: "Levels"
category_undefined: "Uncategorized"
current_xp_prefix: "" current_xp_prefix: ""
current_xp_postfix: " in total" current_xp_postfix: " in total"
new_xp_prefix: "" new_xp_prefix: ""
@ -1231,8 +1219,6 @@
left_xp_postfix: "" left_xp_postfix: ""
account: account:
recently_played: "Recently Played"
no_recent_games: "No games played during the past two weeks."
payments: "Payments" payments: "Payments"
prepaid_codes: "Prepaid Codes" prepaid_codes: "Prepaid Codes"
purchased: "Purchased" purchased: "Purchased"

View file

@ -839,16 +839,16 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
playtime: "Tiempo de juego" playtime: "Tiempo de juego"
last_played: "Último jugado" last_played: "Último jugado"
leagues_explanation: "Juega en una liga contra otros miembros del clan en estas instancias de arena multijugador." leagues_explanation: "Juega en una liga contra otros miembros del clan en estas instancias de arena multijugador."
# track_concepts1: "Track concepts" track_concepts1: "Haga un seguimiento de los conceptos"
track_concepts2a: "aprendidos por cada estudiante" track_concepts2a: "aprendidos por cada estudiante"
track_concepts2b: "aprendidos por cada miembro" track_concepts2b: "aprendidos por cada miembro"
# track_concepts3a: "Track levels completados por cada estudiante" track_concepts3a: "Haga un seguimiento de los niveles completados por cada estudiante"
# track_concepts3b: "Track levels completados por cada miembro" track_concepts3b: "Haga un seguimiento de los niveles completados por cada miembro"
track_concepts4a: "Ve a tus estudiantes'" track_concepts4a: "Ve a tus estudiantes'"
track_concepts4b: "Ve a tus miembros'" track_concepts4b: "Ve a tus miembros'"
track_concepts5: "soluciones" track_concepts5: "soluciones"
# track_concepts6a: "Sort students by name or progress" track_concepts6a: "Ordene a sus estudiantes por nombre o progreso"
# track_concepts6b: "Sort members by name or progress" track_concepts6b: "Ordene a sus miembros por nombre o progreso"
track_concepts7: "Requiere invitación" track_concepts7: "Requiere invitación"
track_concepts8: "para unirse" track_concepts8: "para unirse"
private_require_sub: "Los clanes privados requieren una subscripción para crearlos o unírseles." private_require_sub: "Los clanes privados requieren una subscripción para crearlos o unírseles."
@ -886,7 +886,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
invite_students: "Invite a sus estudiantes a unirse a este grupo." invite_students: "Invite a sus estudiantes a unirse a este grupo."
invite_link_header: "Enlace para unirse al curso" invite_link_header: "Enlace para unirse al curso"
invite_link_p_1: "Proporciones este enalce a los estudiantes que desee que se unan al curso." invite_link_p_1: "Proporciones este enalce a los estudiantes que desee que se unan al curso."
# invite_link_p_2: "Or have us email them directly:" invite_link_p_2: "O envíenoslos directamente mediante el correo electrónico:"
capacity_used: "Espacios de curso usados:" capacity_used: "Espacios de curso usados:"
enter_emails: "Introducir los emails de los estudiantes a invitar, uno por línea" enter_emails: "Introducir los emails de los estudiantes a invitar, uno por línea"
send_invites: "¿Mandar Invitaciones?" send_invites: "¿Mandar Invitaciones?"
@ -1269,13 +1269,13 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
purchase_button: "Enviar Adquisición" purchase_button: "Enviar Adquisición"
your_codes: "Tus Códigos:" # {change} your_codes: "Tus Códigos:" # {change}
redeem_codes: "Reclamar un Código de Subscripción" redeem_codes: "Reclamar un Código de Subscripción"
# prepaid_code: "Prepaid Code" prepaid_code: "Código Prepagado"
# lookup_code: "Lookup prepaid code" # lookup_code: "Lookup prepaid code"
# apply_account: "Apply to your account" # apply_account: "Apply to your account"
# copy_link: "You can copy the code's link and send it to someone." # copy_link: "You can copy the code's link and send it to someone."
# quantity: "Quantity" quantity: "Cantidad"
# redeemed: "Redeemed" redeemed: "Reclamado"
# no_codes: "No codes yet!" no_codes: "¡Aún sin códigos!"
loading_error: loading_error:
could_not_load: "Error cargando del servidor" could_not_load: "Error cargando del servidor"

View file

@ -40,7 +40,7 @@ block content
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name') a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name')
else else
a(href="/clans/#{clan.id}")= clan.get('name') a(href="/clans/#{clan.id}")= clan.get('name')
td= clan.get('members').length td= clan.get('memberCount')
td td
if idNameMap && idNameMap[clan.get('ownerID')] if idNameMap && idNameMap[clan.get('ownerID')]
a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')] a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')]
@ -70,7 +70,7 @@ block content
a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name') a(href="/clans/#{clan.id}", style='font-weight:bold')= clan.get('name')
else else
a(href="/clans/#{clan.id}")= clan.get('name') a(href="/clans/#{clan.id}")= clan.get('name')
td= clan.get('members').length td= clan.get('memberCount')
td td
if idNameMap && idNameMap[clan.get('ownerID')] if idNameMap && idNameMap[clan.get('ownerID')]
a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')] a(href="/user/#{clan.get('ownerID')}")= idNameMap[clan.get('ownerID')]

View file

@ -3,7 +3,7 @@ extends /templates/base
block content block content
h2 Hour of Code(Combat) h2 Hour of Code(Combat)
p p
strong Hi Teachers! strong Hi Teachers!
p We're excited to participate in Hour of Code this year! p We're excited to participate in Hour of Code this year!
p We've set up an Introduction to Computer Science course, just for you. p We've set up an Introduction to Computer Science course, just for you.
@ -12,12 +12,12 @@ block content
ol ol
li li
span.spr Navigate to the span.spr Navigate to the
a.spr(href='/courses/teachers?hoc=true') Courses a(href='/courses/teachers?hoc=true') Courses
span page span.spl page
li Click the green 'Get FREE course' button under Introduction to Computer Science li Click the green 'Get FREE course' button under Introduction to Computer Science
li Follow the enrollment instructions li Follow the enrollment instructions
li Add students via the 'Add Students' tab li Add students via the 'Add Students' tab
p p
span.spr If you have any problems, please email span.spr If you have any problems, please email
a(href='mailto:team@codecombat.com') team@codecombat.com a(href='mailto:team@codecombat.com') team@codecombat.com
br br
@ -66,15 +66,15 @@ block content
p(data-i18n="teachers.monitor_progress_5") p(data-i18n="teachers.monitor_progress_5")
h4(data-i18n="teachers.sub_includes_7") h4(data-i18n="teachers.sub_includes_7")
ul ul
li li
strong(data-i18n="clans.track_concepts1") strong(data-i18n="clans.track_concepts1")
span.spl(data-i18n="clans.track_concepts2a") span.spl(data-i18n="clans.track_concepts2a")
li(data-i18n="clans.track_concepts3a") li(data-i18n="clans.track_concepts3a")
li li
span(data-i18n="clans.track_concepts4a") span(data-i18n="clans.track_concepts4a")
strong.spl(data-i18n="clans.track_concepts5") strong.spl(data-i18n="clans.track_concepts5")
li(data-i18n="clans.track_concepts6a") li(data-i18n="clans.track_concepts6a")
li li
strong(data-i18n="clans.track_concepts7") strong(data-i18n="clans.track_concepts7")
span.spl(data-i18n="clans.track_concepts8") span.spl(data-i18n="clans.track_concepts8")
p p
@ -144,7 +144,7 @@ block content
span.spr.spl span.spr.spl
a(href='/account/subscription', data-i18n="teachers.how_much_2") a(href='/account/subscription', data-i18n="teachers.how_much_2")
span.spr.spl(data-i18n="teachers.how_much_3") span.spr.spl(data-i18n="teachers.how_much_3")
p p
span.spr(data-i18n="teachers.how_much_5") span.spr(data-i18n="teachers.how_much_5")
a(href='mailto:team@codecombat.com') team@codecombat.com a(href='mailto:team@codecombat.com') team@codecombat.com
span.spl(data-i18n="teachers.how_much_6") span.spl(data-i18n="teachers.how_much_6")
@ -153,7 +153,7 @@ block content
a(href='/account/subscription', data-i18n="subscribe.group_discounts") a(href='/account/subscription', data-i18n="subscribe.group_discounts")
p(data-i18n="subscribe.group_discounts_1") p(data-i18n="subscribe.group_discounts_1")
table.table.table-condensed.discount-table table.table.table-condensed.discount-table
tr tr
td(data-i18n="subscribe.group_discounts_1st") td(data-i18n="subscribe.group_discounts_1st")
td(data-i18n="subscribe.group_discounts_full") td(data-i18n="subscribe.group_discounts_full")
tr tr

View file

@ -64,7 +64,6 @@ module.exports = class ClanDetailsView extends RootView
@supermodel.loadModel @clan, 'clan', cache: false @supermodel.loadModel @clan, 'clan', cache: false
@supermodel.loadCollection(@members, 'members', {cache: false}) @supermodel.loadCollection(@members, 'members', {cache: false})
@supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false}) @supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false})
@supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false})
getRenderData: -> getRenderData: ->
context = super() context = super()
@ -115,7 +114,7 @@ module.exports = class ClanDetailsView extends RootView
lastLevelIndex++ lastLevelIndex++
levelCount++ levelCount++
@sortMembers(highestUserLevelCountMap, userConceptsMap) if @clan.get('dashboardType') is 'premium' @sortMembers(highestUserLevelCountMap, userConceptsMap)# if @clan.get('dashboardType') is 'premium'
context.members = @members?.models ? [] context.members = @members?.models ? []
context.lastUserCampaignLevelMap = lastUserCampaignLevelMap context.lastUserCampaignLevelMap = lastUserCampaignLevelMap
context.showExpandedProgress = maxLastUserCampaignLevel <= 30 or @showExpandedProgress context.showExpandedProgress = maxLastUserCampaignLevel <= 30 or @showExpandedProgress
@ -207,6 +206,8 @@ module.exports = class ClanDetailsView extends RootView
@owner = new User _id: @clan.get('ownerID') @owner = new User _id: @clan.get('ownerID')
@listenTo @owner, 'sync', => @render?() @listenTo @owner, 'sync', => @render?()
@supermodel.loadModel @owner, 'owner', cache: false @supermodel.loadModel @owner, 'owner', cache: false
if @clan.get("dashboardType") is "premium"
@supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false})
@render?() @render?()
onMembersSync: -> onMembersSync: ->

View file

@ -43,8 +43,8 @@ module.exports = class ClansView extends RootView
@idNameMap = {} @idNameMap = {}
sortClanList = (a, b) -> sortClanList = (a, b) ->
if a.get('members').length isnt b.get('members').length if a.get('memberCount') isnt b.get('memberCount')
if a.get('members').length < b.get('members').length then 1 else -1 if a.get('memberCount') < b.get('memberCount') then 1 else -1
else else
b.id.localeCompare(a.id) b.id.localeCompare(a.id)
@publicClans = new CocoCollection([], { url: '/db/clan/-/public', model: Clan, comparator: sortClanList }) @publicClans = new CocoCollection([], { url: '/db/clan/-/public', model: Clan, comparator: sortClanList })

View file

@ -448,8 +448,6 @@ module.exports = class HeroVictoryModal extends ModalView
navigationEvent = route: nextLevelLink, viewClass: viewClass, viewArgs: viewArgs navigationEvent = route: nextLevelLink, viewClass: viewClass, viewArgs: viewArgs
if @level.get('slug') is 'lost-viking' and not (me.get('age') in ['0-13', '14-17']) if @level.get('slug') is 'lost-viking' and not (me.get('age') in ['0-13', '14-17'])
@showOffer navigationEvent @showOffer navigationEvent
else if @level.get('slug') is 'a-mayhem-of-munchkins' and not (me.get('age') in ['0-13']) and not options.showLeaderboard
@showOffer navigationEvent
else else
Backbone.Mediator.publish 'router:navigate', navigationEvent Backbone.Mediator.publish 'router:navigate', navigationEvent

View file

@ -263,8 +263,10 @@ module.exports = class SpellView extends CocoView
@ace.commands.on 'exec', (e) => @ace.commands.on 'exec', (e) =>
# When pressing enter with an active selection, just make a new line under it. # When pressing enter with an active selection, just make a new line under it.
if e.command.name is 'enter-skip-delimiters' if e.command.name is 'enter-skip-delimiters'
e.editor.execCommand 'gotolineend' selection = @ace.selection.getRange()
return true unless selection.start.column is selection.end.column and selection.start.row is selection.end.row
e.editor.execCommand 'gotolineend'
return true
fillACE: -> fillACE: ->
@ace.setValue @spell.source @ace.setValue @spell.source

View file

@ -10,6 +10,8 @@ LevelSessionHandler = require '../levels/sessions/level_session_handler'
User = require '../users/User' User = require '../users/User'
UserHandler = require '../users/user_handler' UserHandler = require '../users/user_handler'
memberLimit = 200
ClanHandler = class ClanHandler extends Handler ClanHandler = class ClanHandler extends Handler
modelClass: Clan modelClass: Clan
jsonSchema: require '../../app/schemas/models/clan.schema' jsonSchema: require '../../app/schemas/models/clan.schema'
@ -94,17 +96,15 @@ ClanHandler = class ClanHandler extends Handler
getMemberAchievements: (req, res, clanID) -> getMemberAchievements: (req, res, clanID) ->
# TODO: add tests # TODO: add tests
memberLimit = 200
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless clan return @sendNotFoundError(res) unless clan
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
User.find {_id: {$in: memberIDs}}, 'nameLower', {sort: {nameLower: 1}}, (err, users) => User.find {_id: {$in: memberIDs}}, 'nameLower', {limit: memberLimit}, (err, users) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
memberIDs = [] memberIDs = []
for user in users for user in users
memberIDs.push user.id memberIDs.push user.id
break unless memberIDs.length < memberLimit
EarnedAchievement.find {user: {$in: memberIDs}}, 'achievementName user', (err, documents) => EarnedAchievement.find {user: {$in: memberIDs}}, 'achievementName user', (err, documents) =>
return @sendDatabaseError(res, err) if err? return @sendDatabaseError(res, err) if err?
cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents) cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents)
@ -115,8 +115,8 @@ ClanHandler = class ClanHandler extends Handler
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless clan return @sendNotFoundError(res) unless clan
memberIDs = clan.get('members') ? [] memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {sort: {nameLower: 1}}, (err, users) => User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {}, (err, users) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
cleandocs = (UserHandler.formatEntity(req, doc) for doc in users) cleandocs = (UserHandler.formatEntity(req, doc) for doc in users)
@sendSuccess(res, cleandocs) @sendSuccess(res, cleandocs)
@ -124,12 +124,12 @@ ClanHandler = class ClanHandler extends Handler
getMemberSessions: (req, res, clanID) -> getMemberSessions: (req, res, clanID) ->
# TODO: add tests # TODO: add tests
# TODO: restrict information returned based on clan type # TODO: restrict information returned based on clan type
memberLimit = 200
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless clan return @sendNotFoundError(res) unless clan
return @sendForbiddenError(res) unless clan.get('dashboardType') is 'premium'
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
User.find {_id: {$in: memberIDs}}, 'name', {sort: {name: 1}}, (err, users) => User.find {_id: {$in: memberIDs}}, 'name', {limit: memberLimit}, (err, users) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
memberIDs = [] memberIDs = []
for user in users for user in users
@ -143,7 +143,7 @@ ClanHandler = class ClanHandler extends Handler
getPublicClans: (req, res) -> getPublicClans: (req, res) ->
# Return 100 public clans, sorted by member count, created date # Return 100 public clans, sorted by member count, created date
query = [{ $match : {type : 'public'} }] query = [{ $match : {type : 'public'} }]
query.push {$project : {_id: 1, name: 1, slug: 1, type: 1, description: 1, members: 1, memberCount: {$size: "$members"}, ownerID: 1}} 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 {$sort: { memberCount: -1, _id: -1 }}
query.push {$limit: 100} query.push {$limit: 100}
Clan.aggregate(query).exec (err, documents) => Clan.aggregate(query).exec (err, documents) =>