mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-01 03:16:56 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
6641e60f2d
4 changed files with 147 additions and 45 deletions
|
@ -73,7 +73,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
creating: "账户创建中……"
|
creating: "账户创建中……"
|
||||||
sign_up: "注册"
|
sign_up: "注册"
|
||||||
log_in: "登录"
|
log_in: "登录"
|
||||||
# social_signup: "Or, you can sign up through Facebook or G+:"
|
social_signup: "或者,你可以通过Facebook或G+注册:"
|
||||||
|
|
||||||
home:
|
home:
|
||||||
slogan: "通过游戏学习 Javascript"
|
slogan: "通过游戏学习 Javascript"
|
||||||
|
@ -114,7 +114,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
forum_page: "我们的论坛"
|
forum_page: "我们的论坛"
|
||||||
forum_suffix: ""
|
forum_suffix: ""
|
||||||
send: "反馈意见"
|
send: "反馈意见"
|
||||||
# contact_candidate: "Contact Candidate"
|
contact_candidate: "联系参选人"
|
||||||
# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 18% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns."
|
# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 18% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns."
|
||||||
|
|
||||||
diplomat_suggestion:
|
diplomat_suggestion:
|
||||||
|
@ -128,13 +128,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
wizard_settings:
|
wizard_settings:
|
||||||
title: "设置向导"
|
title: "设置向导"
|
||||||
customize_avatar: "设置你的头像"
|
customize_avatar: "设置你的头像"
|
||||||
# active: "Active"
|
active: "启用"
|
||||||
# color: "Color"
|
color: "颜色"
|
||||||
# group: "Group"
|
group: "类别"
|
||||||
clothes: "衣服"
|
clothes: "衣服"
|
||||||
trim: "条纹"
|
trim: "条纹"
|
||||||
cloud: "云"
|
cloud: "云"
|
||||||
# team: "Team"
|
team: "队伍"
|
||||||
spell: "魔法球"
|
spell: "魔法球"
|
||||||
boots: "鞋子"
|
boots: "鞋子"
|
||||||
hue: "颜色"
|
hue: "颜色"
|
||||||
|
@ -177,27 +177,27 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
profile_for_suffix: ""
|
profile_for_suffix: ""
|
||||||
# approved: "Approved"
|
# approved: "Approved"
|
||||||
# not_approved: "Not Approved"
|
# not_approved: "Not Approved"
|
||||||
# looking_for: "Looking for:"
|
looking_for: "寻找"
|
||||||
# last_updated: "Last updated:"
|
last_updated: "最后一次更新:"
|
||||||
# contact: "Contact"
|
contact: "联系"
|
||||||
# work_experience: "Work Experience"
|
work_experience: "工作经验"
|
||||||
# education: "Education"
|
education: "教育程度"
|
||||||
# our_notes: "Our Notes"
|
# our_notes: "Our Notes"
|
||||||
# projects: "Projects"
|
projects: "项目"
|
||||||
|
|
||||||
# employers:
|
# employers:
|
||||||
# want_to_hire_our_players: "Want to hire expert CodeCombat players?"
|
want_to_hire_our_players: "想要雇用CodeCombat上的专业玩家?"
|
||||||
# contact_george: "Contact George to see our candidates"
|
# contact_george: "Contact George to see our candidates"
|
||||||
# candidates_count_prefix: "We currently have "
|
candidates_count_prefix: "我们当前有 "
|
||||||
# candidates_count_many: "many"
|
candidates_count_many: "很多"
|
||||||
# candidates_count_suffix: "highly skilled and vetted developers looking for work."
|
# candidates_count_suffix: "highly skilled and vetted developers looking for work."
|
||||||
# candidate_name: "Name"
|
candidate_name: "姓名"
|
||||||
# candidate_location: "Location"
|
candidate_location: "地点"
|
||||||
# candidate_looking_for: "Looking For"
|
candidate_looking_for: "寻找"
|
||||||
# candidate_role: "Role"
|
candidate_role: "角色"
|
||||||
# candidate_top_skills: "Top Skills"
|
candidate_top_skills: "高级技能"
|
||||||
# candidate_years_experience: "Yrs Exp"
|
candidate_years_experience: "多年工作经验"
|
||||||
# candidate_last_updated: "Last Updated"
|
candidate_last_updated: "最后一次更新"
|
||||||
|
|
||||||
play_level:
|
play_level:
|
||||||
level_load_error: "关卡不能载入: "
|
level_load_error: "关卡不能载入: "
|
||||||
|
@ -250,17 +250,17 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
editor_config_title: "编辑器配置"
|
editor_config_title: "编辑器配置"
|
||||||
editor_config_language_label: "编程语言"
|
editor_config_language_label: "编程语言"
|
||||||
editor_config_language_description: "请输入你想写的编程语言."
|
editor_config_language_description: "请输入你想写的编程语言."
|
||||||
# editor_config_keybindings_label: "Key Bindings"
|
editor_config_keybindings_label: "按键设置s"
|
||||||
# editor_config_keybindings_default: "Default (Ace)"
|
editor_config_keybindings_default: "默认 (Ace)"
|
||||||
# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors."
|
# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors."
|
||||||
# editor_config_invisibles_label: "Show Invisibles"
|
editor_config_invisibles_label: "显示隐藏的"
|
||||||
# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs."
|
editor_config_invisibles_description: "显示诸如空格或TAB键。"
|
||||||
# editor_config_indentguides_label: "Show Indent Guides"
|
editor_config_indentguides_label: "显示缩进提示"
|
||||||
# editor_config_indentguides_description: "Displays vertical lines to see indentation better."
|
editor_config_indentguides_description: "显示一条竖线以使缩进更明显。"
|
||||||
# editor_config_behaviors_label: "Smart Behaviors"
|
# editor_config_behaviors_label: "Smart Behaviors"
|
||||||
# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes."
|
# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes."
|
||||||
loading_ready: "载入完成!"
|
loading_ready: "载入完成!"
|
||||||
# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor."
|
tip_insert_positions: "使用Shift+左键来插入拼写编辑器。"
|
||||||
tip_toggle_play: "用 Ctrl+P 来暂停或继续"
|
tip_toggle_play: "用 Ctrl+P 来暂停或继续"
|
||||||
tip_scrub_shortcut: "用 Ctrl+[ 和 Ctrl+] 来倒退和快进."
|
tip_scrub_shortcut: "用 Ctrl+[ 和 Ctrl+] 来倒退和快进."
|
||||||
tip_guide_exists: "点击页面上方的指南, 可以获得更多有用信息."
|
tip_guide_exists: "点击页面上方的指南, 可以获得更多有用信息."
|
||||||
|
@ -285,15 +285,15 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
tip_no_try: "做. 或是不做. 这世上不存在'尝试'这种东西. - 尤达大师"
|
tip_no_try: "做. 或是不做. 这世上不存在'尝试'这种东西. - 尤达大师"
|
||||||
# tip_patience: "Patience you must have, young Padawan. - Yoda"
|
# tip_patience: "Patience you must have, young Padawan. - Yoda"
|
||||||
tip_documented_bug: "一个写在文档里的漏洞不算漏洞, 那是个功能."
|
tip_documented_bug: "一个写在文档里的漏洞不算漏洞, 那是个功能."
|
||||||
tip_impossible: "It always seems impossible until it's done. - Nelson Mandela"
|
tip_impossible: "在事情未完成之前,一切都看似不可能. - 纳尔逊·曼德拉"
|
||||||
tip_talk_is_cheap: "多说无用, 亮出你的代码. - Linus Torvalds"
|
tip_talk_is_cheap: "多说无用, 亮出你的代码. - Linus Torvalds"
|
||||||
# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
|
# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
|
||||||
time_current: "现在:"
|
time_current: "现在:"
|
||||||
time_total: "最大:"
|
time_total: "最大:"
|
||||||
time_goto: "跳到:"
|
time_goto: "跳到:"
|
||||||
# infinite_loop_try_again: "Try Again"
|
infinite_loop_try_again: "请重试"
|
||||||
# infinite_loop_reset_level: "Reset Level"
|
infinite_loop_reset_level: "重置等级"
|
||||||
# infinite_loop_comment_out: "Comment Out My Code"
|
infinite_loop_comment_out: "为我的代码添加注释"
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
av_title: "管理员视图"
|
av_title: "管理员视图"
|
||||||
|
@ -361,7 +361,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
thang_search_title: "在这里搜索物品类型"
|
thang_search_title: "在这里搜索物品类型"
|
||||||
level_search_title: "在这里搜索关卡"
|
level_search_title: "在这里搜索关卡"
|
||||||
signup_to_create: "注册之后就可以创建一个新的关卡"
|
signup_to_create: "注册之后就可以创建一个新的关卡"
|
||||||
# read_only_warning2: "Note: you can't save any edits here, because you're not logged in."
|
read_only_warning2: "提示:你不能保存任何编辑,因为你没有登陆"
|
||||||
|
|
||||||
article:
|
article:
|
||||||
edit_btn_preview: "预览"
|
edit_btn_preview: "预览"
|
||||||
|
@ -373,13 +373,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
body: "正文"
|
body: "正文"
|
||||||
version: "版本"
|
version: "版本"
|
||||||
commit_msg: "提交信息"
|
commit_msg: "提交信息"
|
||||||
# version_history: "Version History"
|
version_history: "版本历史"
|
||||||
version_history_for: "版本历史: "
|
version_history_for: "版本历史: "
|
||||||
result: "结果"
|
result: "结果"
|
||||||
results: "结果"
|
results: "结果"
|
||||||
description: "描述"
|
description: "描述"
|
||||||
or: "或"
|
or: "或"
|
||||||
# subject: "Subject"
|
subject: "主题"
|
||||||
email: "邮件"
|
email: "邮件"
|
||||||
password: "密码"
|
password: "密码"
|
||||||
message: "信息"
|
message: "信息"
|
||||||
|
@ -395,7 +395,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
easy: "容易"
|
easy: "容易"
|
||||||
medium: "中等"
|
medium: "中等"
|
||||||
hard: "困难"
|
hard: "困难"
|
||||||
# player: "Player"
|
player: "玩家"
|
||||||
|
|
||||||
about:
|
about:
|
||||||
who_is_codecombat: "什么是 CodeCombat?"
|
who_is_codecombat: "什么是 CodeCombat?"
|
||||||
|
@ -538,7 +538,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
scribe_introduction_url_mozilla: "Mozilla 开发者社区"
|
scribe_introduction_url_mozilla: "Mozilla 开发者社区"
|
||||||
# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you."
|
# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you."
|
||||||
# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others."
|
# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others."
|
||||||
# contact_us_url: "Contact us"
|
contact_us_url: "联系我们"
|
||||||
scribe_join_description: "介绍一下你自己, 比如你的编程经历和你喜欢写什么东西, 我们将从这里开始了解你!!"
|
scribe_join_description: "介绍一下你自己, 比如你的编程经历和你喜欢写什么东西, 我们将从这里开始了解你!!"
|
||||||
more_about_scribe: "了解如何成为一名文书"
|
more_about_scribe: "了解如何成为一名文书"
|
||||||
scribe_subscribe_desc: "通过电子邮件获得写作新文档的通知。"
|
scribe_subscribe_desc: "通过电子邮件获得写作新文档的通知。"
|
||||||
|
@ -610,7 +610,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
summary_wins: " 胜利, "
|
summary_wins: " 胜利, "
|
||||||
summary_losses: " 失败"
|
summary_losses: " 失败"
|
||||||
rank_no_code: "没有新代码可供评分"
|
rank_no_code: "没有新代码可供评分"
|
||||||
# rank_my_game: "Rank My Game!"
|
rank_my_game: "为我的游戏评分!"
|
||||||
rank_submitting: "正在提交..."
|
rank_submitting: "正在提交..."
|
||||||
# rank_submitted: "Submitted for Ranking"
|
# rank_submitted: "Submitted for Ranking"
|
||||||
rank_failed: "评分失败"
|
rank_failed: "评分失败"
|
||||||
|
@ -665,7 +665,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
gplus_friends: "G+ 朋友"
|
gplus_friends: "G+ 朋友"
|
||||||
# gplus_friend_sessions: "G+ Friend Sessions"
|
# gplus_friend_sessions: "G+ Friend Sessions"
|
||||||
leaderboard: "排行榜"
|
leaderboard: "排行榜"
|
||||||
# user_schema: "User Schema"
|
user_schema: "用户模式"
|
||||||
# user_profile: "User Profile"
|
user_profile: "User Profile"
|
||||||
# patches: "Patches"
|
patches: "补丁"
|
||||||
# model: "Model"
|
# model: "Model"
|
||||||
|
|
|
@ -255,7 +255,7 @@ module.exports = class ThangsTabView extends View
|
||||||
# @thangsTreema.deselectAll()
|
# @thangsTreema.deselectAll()
|
||||||
|
|
||||||
selectAddThang: (e) =>
|
selectAddThang: (e) =>
|
||||||
return unless e? and $(e.target).closest('.editor-level-thangs-tab-view').length
|
return unless e? and $(e.target).closest('#editor-level-thangs-tab-view').length
|
||||||
if e then target = $(e.target) else target = @$el.find('.add-thangs-palette') # pretend to click on background if no event
|
if e then target = $(e.target) else target = @$el.find('.add-thangs-palette') # pretend to click on background if no event
|
||||||
return true if target.attr('id') is 'surface'
|
return true if target.attr('id') is 'surface'
|
||||||
target = target.closest('.add-thang-palette-icon')
|
target = target.closest('.add-thang-palette-icon')
|
||||||
|
|
103
scripts/mail.coffee
Normal file
103
scripts/mail.coffee
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
do (setupLodash = this) ->
|
||||||
|
GLOBAL._ = require 'lodash'
|
||||||
|
_.str = require 'underscore.string'
|
||||||
|
_.mixin _.str.exports()
|
||||||
|
|
||||||
|
async = require 'async'
|
||||||
|
|
||||||
|
serverSetup = require '../server_setup'
|
||||||
|
sendwithus = require '../server/sendwithus'
|
||||||
|
User = require '../server/users/User.coffee'
|
||||||
|
Level = require '../server/levels/Level.coffee'
|
||||||
|
LevelSession = require '../server/levels/sessions/LevelSession.coffee'
|
||||||
|
|
||||||
|
alreadyEmailed = []
|
||||||
|
|
||||||
|
DEBUGGING = true
|
||||||
|
|
||||||
|
sendInitialRecruitingEmail = ->
|
||||||
|
leaderboards = [
|
||||||
|
{slug: 'brawlwood', team: 'humans', limit: 55, name: "Brawlwood", original: "52d97ecd32362bc86e004e87", majorVersion: 0}
|
||||||
|
{slug: 'brawlwood', team: 'ogres', limit: 40, name: "Brawlwood", original: "52d97ecd32362bc86e004e87", majorVersion: 0}
|
||||||
|
{slug: 'dungeon-arena', team: 'humans', limit: 200, name: "Dungeon Arena", original: "53173f76c269d400000543c2", majorVersion: 0}
|
||||||
|
{slug: 'dungeon-arena', team: 'ogres', limit: 150, name: "Dungeon Arena", original: "53173f76c269d400000543c2", majorVersion: 0}
|
||||||
|
]
|
||||||
|
async.waterfall [
|
||||||
|
(callback) -> async.map leaderboards, grabSessions, callback
|
||||||
|
(sessionLists, callback) -> async.map collapseSessions(sessionLists), grabUser, callback
|
||||||
|
(users, callback) -> async.map users, emailUser, callback
|
||||||
|
], (err, results) ->
|
||||||
|
return console.log "Error:", err if err
|
||||||
|
console.log "Looked at sending to #{results.length} users; sent to #{_.filter(results).length}."
|
||||||
|
console.log "Sent to: ['#{(user.email for user in results when user).join('\', \'')}']"
|
||||||
|
|
||||||
|
grabSessions = (levelInfo, callback) ->
|
||||||
|
queryParameters =
|
||||||
|
level: {original: levelInfo.original, majorVersion: levelInfo.majorVersion}
|
||||||
|
team: levelInfo.team
|
||||||
|
submitted: true
|
||||||
|
sortParameters = totalScore: -1
|
||||||
|
selectString = 'totalScore creator'
|
||||||
|
query = LevelSession
|
||||||
|
.find(queryParameters)
|
||||||
|
.limit(levelInfo.limit)
|
||||||
|
.sort(sortParameters)
|
||||||
|
.select(selectString)
|
||||||
|
.lean()
|
||||||
|
query.exec (err, sessions) ->
|
||||||
|
return callback err if err
|
||||||
|
for session, rank in sessions
|
||||||
|
session.levelInfo = levelInfo
|
||||||
|
session.rank = rank + 1
|
||||||
|
callback null, sessions
|
||||||
|
|
||||||
|
collapseSessions = (sessionLists) ->
|
||||||
|
userRanks = {}
|
||||||
|
for sessionList in sessionLists
|
||||||
|
for session in sessionList
|
||||||
|
ranks = userRanks[session.creator] ? []
|
||||||
|
ranks.push session
|
||||||
|
userRanks[session.creator] = _.sortBy ranks, 'rank'
|
||||||
|
topSessions = []
|
||||||
|
for userID, ranks of userRanks
|
||||||
|
topSessions.push ranks[0]
|
||||||
|
topSessions
|
||||||
|
|
||||||
|
grabUser = (session, callback) ->
|
||||||
|
findParameters = _id: session.creator
|
||||||
|
selectString = 'email emailSubscriptions name jobProfile'
|
||||||
|
query = User
|
||||||
|
.findOne(findParameters)
|
||||||
|
.select(selectString)
|
||||||
|
.lean()
|
||||||
|
query.exec (err, user) ->
|
||||||
|
return callback err if err
|
||||||
|
user.session = session
|
||||||
|
callback null, user
|
||||||
|
|
||||||
|
totalEmailsSent = 0
|
||||||
|
emailUser = (user, callback) ->
|
||||||
|
return callback null, false if user.emails?.recruiting?.enabled is false # TODO: later, obey also "announcements" when that's untangled
|
||||||
|
return callback null, false if user.email in alreadyEmailed
|
||||||
|
return callback null, false if DEBUGGING and (totalEmailsSent > 1 or Math.random() > 0.1)
|
||||||
|
++totalEmailsSent
|
||||||
|
name = if user.firstName and user.lastName then "#{user.firstName}" else user.name
|
||||||
|
name = "Wizard" if not name or name is "Anoner"
|
||||||
|
team = user.session.levelInfo.team
|
||||||
|
team = team.substr(0, team.length - 1)
|
||||||
|
context =
|
||||||
|
email_id: sendwithus.templates.one_time_recruiting_email
|
||||||
|
recipient:
|
||||||
|
address: if DEBUGGING then 'nick@codecombat.com' else user.email
|
||||||
|
name: name
|
||||||
|
email_data:
|
||||||
|
name: name
|
||||||
|
level_name: user.session.levelInfo.name
|
||||||
|
place: "##{user.session.rank}" # like "#31"
|
||||||
|
level_race: team
|
||||||
|
sendwithus.api.send context, (err, result) ->
|
||||||
|
return callback err if err
|
||||||
|
callback null, user
|
||||||
|
|
||||||
|
serverSetup.connectToDatabase()
|
||||||
|
sendInitialRecruitingEmail()
|
|
@ -1,12 +1,10 @@
|
||||||
config = require '../server_config'
|
config = require '../server_config'
|
||||||
sendwithusAPI = require 'sendwithus'
|
sendwithusAPI = require 'sendwithus'
|
||||||
swuAPIKey = config.mail.sendwithusAPIKey
|
swuAPIKey = config.mail.sendwithusAPIKey
|
||||||
queues = require './commons/queue'
|
|
||||||
|
|
||||||
module.exports.setupRoutes = (app) ->
|
module.exports.setupRoutes = (app) ->
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
debug = not config.isProduction
|
debug = not config.isProduction
|
||||||
module.exports.api = new sendwithusAPI swuAPIKey, debug
|
module.exports.api = new sendwithusAPI swuAPIKey, debug
|
||||||
if config.unittest
|
if config.unittest
|
||||||
|
@ -16,3 +14,4 @@ module.exports.templates =
|
||||||
ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'
|
ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'
|
||||||
patch_created: 'tem_xhxuNosLALsizTNojBjNcL'
|
patch_created: 'tem_xhxuNosLALsizTNojBjNcL'
|
||||||
change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG'
|
change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG'
|
||||||
|
one_time_recruiting_email: 'tem_mdFMgtcczHKYu94Jmq68j8'
|
||||||
|
|
Loading…
Reference in a new issue