diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee index 5a6ec9e11..313b790ed 100644 --- a/app/locale/zh-HANS.coffee +++ b/app/locale/zh-HANS.coffee @@ -73,7 +73,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese creating: "账户创建中……" sign_up: "注册" log_in: "登录" -# social_signup: "Or, you can sign up through Facebook or G+:" + social_signup: "或者,你可以通过Facebook或G+注册:" home: slogan: "通过游戏学习 Javascript" @@ -114,7 +114,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese forum_page: "我们的论坛" forum_suffix: "" 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." diplomat_suggestion: @@ -128,13 +128,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese wizard_settings: title: "设置向导" customize_avatar: "设置你的头像" -# active: "Active" -# color: "Color" -# group: "Group" + active: "启用" + color: "颜色" + group: "类别" clothes: "衣服" trim: "条纹" cloud: "云" -# team: "Team" + team: "队伍" spell: "魔法球" boots: "鞋子" hue: "颜色" @@ -177,27 +177,27 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese profile_for_suffix: "" # approved: "Approved" # not_approved: "Not Approved" -# looking_for: "Looking for:" -# last_updated: "Last updated:" -# contact: "Contact" -# work_experience: "Work Experience" -# education: "Education" + looking_for: "寻找" + last_updated: "最后一次更新:" + contact: "联系" + work_experience: "工作经验" + education: "教育程度" # our_notes: "Our Notes" -# projects: "Projects" + projects: "项目" # 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" -# candidates_count_prefix: "We currently have " -# candidates_count_many: "many" + candidates_count_prefix: "我们当前有 " + candidates_count_many: "很多" # candidates_count_suffix: "highly skilled and vetted developers looking for work." -# candidate_name: "Name" -# candidate_location: "Location" -# candidate_looking_for: "Looking For" -# candidate_role: "Role" -# candidate_top_skills: "Top Skills" -# candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" + candidate_name: "姓名" + candidate_location: "地点" + candidate_looking_for: "寻找" + candidate_role: "角色" + candidate_top_skills: "高级技能" + candidate_years_experience: "多年工作经验" + candidate_last_updated: "最后一次更新" play_level: level_load_error: "关卡不能载入: " @@ -250,17 +250,17 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese editor_config_title: "编辑器配置" editor_config_language_label: "编程语言" editor_config_language_description: "请输入你想写的编程语言." -# editor_config_keybindings_label: "Key Bindings" -# editor_config_keybindings_default: "Default (Ace)" + editor_config_keybindings_label: "按键设置s" + editor_config_keybindings_default: "默认 (Ace)" # editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." -# editor_config_invisibles_label: "Show Invisibles" -# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." -# editor_config_indentguides_label: "Show Indent Guides" -# editor_config_indentguides_description: "Displays vertical lines to see indentation better." + editor_config_invisibles_label: "显示隐藏的" + editor_config_invisibles_description: "显示诸如空格或TAB键。" + editor_config_indentguides_label: "显示缩进提示" + editor_config_indentguides_description: "显示一条竖线以使缩进更明显。" # editor_config_behaviors_label: "Smart Behaviors" # editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." 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_scrub_shortcut: "用 Ctrl+[ 和 Ctrl+] 来倒退和快进." tip_guide_exists: "点击页面上方的指南, 可以获得更多有用信息." @@ -285,15 +285,15 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese tip_no_try: "做. 或是不做. 这世上不存在'尝试'这种东西. - 尤达大师" # tip_patience: "Patience you must have, young Padawan. - Yoda" tip_documented_bug: "一个写在文档里的漏洞不算漏洞, 那是个功能." - tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" + tip_impossible: "在事情未完成之前,一切都看似不可能. - 纳尔逊·曼德拉" 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" time_current: "现在:" time_total: "最大:" time_goto: "跳到:" -# infinite_loop_try_again: "Try Again" -# infinite_loop_reset_level: "Reset Level" -# infinite_loop_comment_out: "Comment Out My Code" + infinite_loop_try_again: "请重试" + infinite_loop_reset_level: "重置等级" + infinite_loop_comment_out: "为我的代码添加注释" admin: av_title: "管理员视图" @@ -361,7 +361,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese thang_search_title: "在这里搜索物品类型" level_search_title: "在这里搜索关卡" signup_to_create: "注册之后就可以创建一个新的关卡" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." + read_only_warning2: "提示:你不能保存任何编辑,因为你没有登陆" article: edit_btn_preview: "预览" @@ -373,13 +373,13 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese body: "正文" version: "版本" commit_msg: "提交信息" -# version_history: "Version History" + version_history: "版本历史" version_history_for: "版本历史: " result: "结果" results: "结果" description: "描述" or: "或" -# subject: "Subject" + subject: "主题" email: "邮件" password: "密码" message: "信息" @@ -395,7 +395,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese easy: "容易" medium: "中等" hard: "困难" -# player: "Player" + player: "玩家" about: who_is_codecombat: "什么是 CodeCombat?" @@ -538,7 +538,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese 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_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: "介绍一下你自己, 比如你的编程经历和你喜欢写什么东西, 我们将从这里开始了解你!!" more_about_scribe: "了解如何成为一名文书" scribe_subscribe_desc: "通过电子邮件获得写作新文档的通知。" @@ -610,7 +610,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese summary_wins: " 胜利, " summary_losses: " 失败" rank_no_code: "没有新代码可供评分" -# rank_my_game: "Rank My Game!" + rank_my_game: "为我的游戏评分!" rank_submitting: "正在提交..." # rank_submitted: "Submitted for Ranking" rank_failed: "评分失败" @@ -665,7 +665,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese gplus_friends: "G+ 朋友" # gplus_friend_sessions: "G+ Friend Sessions" leaderboard: "排行榜" -# user_schema: "User Schema" -# user_profile: "User Profile" -# patches: "Patches" + user_schema: "用户模式" + user_profile: "User Profile" + patches: "补丁" # model: "Model" diff --git a/app/views/editor/level/thangs_tab_view.coffee b/app/views/editor/level/thangs_tab_view.coffee index d19a93eab..7dd3b1637 100644 --- a/app/views/editor/level/thangs_tab_view.coffee +++ b/app/views/editor/level/thangs_tab_view.coffee @@ -255,7 +255,7 @@ module.exports = class ThangsTabView extends View # @thangsTreema.deselectAll() 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 return true if target.attr('id') is 'surface' target = target.closest('.add-thang-palette-icon') diff --git a/scripts/mail.coffee b/scripts/mail.coffee new file mode 100644 index 000000000..140697370 --- /dev/null +++ b/scripts/mail.coffee @@ -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() diff --git a/server/sendwithus.coffee b/server/sendwithus.coffee index 04d8205c3..1f8145eb1 100644 --- a/server/sendwithus.coffee +++ b/server/sendwithus.coffee @@ -1,12 +1,10 @@ config = require '../server_config' sendwithusAPI = require 'sendwithus' swuAPIKey = config.mail.sendwithusAPIKey -queues = require './commons/queue' module.exports.setupRoutes = (app) -> return - debug = not config.isProduction module.exports.api = new sendwithusAPI swuAPIKey, debug if config.unittest @@ -16,3 +14,4 @@ module.exports.templates = ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4' patch_created: 'tem_xhxuNosLALsizTNojBjNcL' change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG' + one_time_recruiting_email: 'tem_mdFMgtcczHKYu94Jmq68j8'