Merge remote-tracking branch 'origin/master'

This commit is contained in:
Scott Erickson 2015-10-12 16:47:59 -07:00
commit 66650452b2
14 changed files with 224 additions and 172 deletions

View file

@ -96,6 +96,8 @@ module.exports = class CocoRouter extends Backbone.Router
'github/*path': 'routeToServer' 'github/*path': 'routeToServer'
'hoc': go('courses/CoursesView')
'i18n': go('i18n/I18NHomeView') 'i18n': go('i18n/I18NHomeView')
'i18n/thang/:handle': go('i18n/I18NEditThangTypeView') 'i18n/thang/:handle': go('i18n/I18NEditThangTypeView')
'i18n/component/:handle': go('i18n/I18NEditComponentView') 'i18n/component/:handle': go('i18n/I18NEditComponentView')

View file

@ -913,7 +913,7 @@
see_the: "See the" see_the: "See the"
more_info: "for more information." more_info: "for more information."
choose_course: "Choose Your Course:" choose_course: "Choose Your Course:"
enter_code: "Enter an unlock code" enter_code: "Enter an unlock code to join an existing class" # {change}
enter_code1: "Enter unlock code" enter_code1: "Enter unlock code"
enroll: "Enroll" enroll: "Enroll"
pick_from_classes: "Pick from your current classes" pick_from_classes: "Pick from your current classes"

View file

@ -304,7 +304,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
tip_morale_improves: "在士气提升之前会一直进行加载。" tip_morale_improves: "在士气提升之前会一直进行加载。"
tip_all_species: "我们相信每一个人都有同等的机会学习编程" tip_all_species: "我们相信每一个人都有同等的机会学习编程"
tip_reticulating: "网格状锯齿。(指Maxis开发的许多游戏如《模拟城市》、《孢子》中加载进程中跑动时出现的卡顿现象)" tip_reticulating: "网格状锯齿。(指Maxis开发的许多游戏如《模拟城市》、《孢子》中加载进程中跑动时出现的卡顿现象)"
tip_harry: "巫师, " tip_harry: "你是一名巫师, "
tip_great_responsibility: "更强的编程技巧也意味着有更高的责任来进行调试。" tip_great_responsibility: "更强的编程技巧也意味着有更高的责任来进行调试。"
tip_munchkin: "如果您不吃掉您的蔬菜, 一个小矮人将在您睡着之后来找您。" tip_munchkin: "如果您不吃掉您的蔬菜, 一个小矮人将在您睡着之后来找您。"
tip_binary: "这个世界上只有10种人: 那些懂二进制的, 还有那些不懂二进制的。" tip_binary: "这个世界上只有10种人: 那些懂二进制的, 还有那些不懂二进制的。"
@ -464,7 +464,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
was_free_until: "您有过一个免费订阅,直到" was_free_until: "您有过一个免费订阅,直到"
managed_subs: "管理订阅" managed_subs: "管理订阅"
managed_subs_desc: "为其他玩家(学生、儿童等)添加订阅。" managed_subs_desc: "为其他玩家(学生、儿童等)添加订阅。"
managed_subs_desc_2: "收件人必须有一个与您提供的电子邮件地址相关联的codecombat帐户。" managed_subs_desc_2: "收件人必须有一个与您提供的电子邮件地址相关联的CodeCombat帐户。"
group_discounts: "团购价" group_discounts: "团购价"
group_discounts_1: "我们还为批量订阅提供团购价" group_discounts_1: "我们还为批量订阅提供团购价"
group_discounts_1st: "1个订阅" group_discounts_1st: "1个订阅"
@ -673,7 +673,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
under: "低于" under: "低于"
other: "其他:" other: "其他:"
amount_students: "请问您有多少学生需要教导?" amount_students: "请问您有多少学生需要教导?"
hear_about: "您是怎么知道CodeComabat的" hear_about: "您是怎么知道CodeCombat的"
fill_fields: "请填写所有问题。" fill_fields: "请填写所有问题。"
thanks: "非常感谢!我们会很快寄给您设置说明。" thanks: "非常感谢!我们会很快寄给您设置说明。"
@ -1207,7 +1207,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
recently_played: "最近玩过的关卡" recently_played: "最近玩过的关卡"
no_recent_games: "最近两个星期没有玩过游戏。" no_recent_games: "最近两个星期没有玩过游戏。"
payments: "支付方式" payments: "支付方式"
# prepaid: "Prepaid" prepaid: "预付费"
purchased: "已购买" purchased: "已购买"
sale: "促销" sale: "促销"
subscription: "订阅" subscription: "订阅"

View file

@ -602,7 +602,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
intro_2: "無需經驗!" intro_2: "無需經驗!"
free_title: "要多少錢?" free_title: "要多少錢?"
cost_china: "CodeCombat的前5個關卡在中國是免費的在這之後需花費每月9.99美元來訪問我們架設在中國專屬服務器上的190多個關卡。" # Deprecated cost_china: "CodeCombat的前5個關卡在中國是免費的在這之後需花費每月9.99美元來訪問我們架設在中國專屬服務器上的190多個關卡。" # Deprecated
# cost_premium_server: "CodeCombat is free for the first five levels, after which it costs $9.99 USD per month for access to our other 190+ levels on our exclusive country-specific servers." cost_premium_server: "CodeCombat的前5個關卡在中國是免費的在這之後需花費每月9.99美元來訪問我們架設在中國專屬服務器上的190多個關卡。"
free_1: "有110多個覆蓋了所有理論的免費關卡。" free_1: "有110多個覆蓋了所有理論的免費關卡。"
free_2: "包月訂閱可以訪問視頻教程和額外的練習關卡。" free_2: "包月訂閱可以訪問視頻教程和額外的練習關卡。"
teacher_subs_title: "教師可免費訂閱!" teacher_subs_title: "教師可免費訂閱!"
@ -673,7 +673,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
under: "低於" under: "低於"
other: "其他:" other: "其他:"
amount_students: "請問您有多少學生需要教導?" amount_students: "請問您有多少學生需要教導?"
hear_about: "您是怎麼知道CodeComabat的" hear_about: "您是怎麼知道CodeCombat的"
fill_fields: "請填寫所有問題。" fill_fields: "請填寫所有問題。"
thanks: "非常感謝!我們會很快寄給您設置說明。" thanks: "非常感謝!我們會很快寄給您設置說明。"
@ -835,93 +835,94 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
last_played: "最後玩了" last_played: "最後玩了"
leagues_explanation: "在部落裡與其他成員組成聯盟一起參加下面的多人競技場。" leagues_explanation: "在部落裡與其他成員組成聯盟一起參加下面的多人競技場。"
# courses:
# course: "Course" courses:
# courses: "courses" course: "課程"
# not_enrolled: "You are not enrolled in this course." courses: "課程"
# visit_pref: "Please visit the" not_enrolled: "您没有註冊這一節課。"
# visit_suf: "page to enroll." visit_pref: "請到這個"
# select_class: "Select one of your classes" visit_suf: "網頁註冊。"
# unnamed: "*unnamed*" select_class: "請選其中一門課堂"
# select: "Select" unnamed: "*未命名*"
# unnamed_class: "Unnamed Class" select: "選擇"
# edit_settings: "edit class settings" unnamed_class: "課堂未命名"
# edit_settings1: "Edit Class Settings" edit_settings: "編輯課堂設定"
# progress: "Class Progress" edit_settings1: "編輯課堂設定"
# add_students: "Add Students" progress: "課堂進度"
# stats: "Statistics" add_students: "添加學生"
# total_students: "Total students:" stats: "統計"
# average_time: "Average level play time:" total_students: "學生人數:"
# total_time: "Total play time:" average_time: "平均遊戲時間:"
# average_levels: "Average levels completed:" total_time: "總計遊戲時間:"
# total_levels: "Total levels completed:" average_levels: "平均完成關卡:"
# furthest_level: "Furthest level completed:" total_levels: "總共完成關卡:"
# concepts_covered: "Concepts Covered" furthest_level: "最高關卡完成:"
# students: "Students" concepts_covered: "課目覆蓋"
# students1: "students" students: "學生"
# expand_details: "Expand details" students1: "個學生。"
# concepts: "Concepts" expand_details: "展開細節"
# levels: "levels" concepts: "課目"
# played: "Played" levels: "關卡"
# play_time: "Play time:" played: "已通關"
# completed: "Completed:" play_time: "遊戲時間:"
# invite_students: "Invite students to join this class." completed: "遊戲時間:"
# invite_link_header: "Link to join course" invite_students: "邀請學生加入此課堂。"
# invite_link_p_1: "Give this link to students you would like to have join the course." invite_link_header: "參與課堂的縺結"
# invite_link_p_2: "Or have us email them directly:" invite_link_p_1: "把這個參與課堂的連結發給你認可的學生。" # there has few problem of my translation
# capacity_used: "Course slots used:" invite_link_p_2: "或讓我們代你直接發送電郵:"
# enter_emails: "Enter student emails to invite, one per line" capacity_used: "Course slots used:"
# send_invites: "Send Invites" enter_emails: "輸入學生電郵地址來邀請,每行一個"
# title: "Title" send_invites: "發送邀請"
# description: "Description" title: "發送邀請"
# languages_available: "Select programming languages available to the class:" description: "描述"
# all_lang: "All Languages" languages_available: "選擇編程語言:"
# show_progress: "Show student progress to everyone in the class" all_lang: "所有編程語言"
# creating_class: "Creating class..." show_progress: "向所有該課堂的人展示學生的進度"
# purchasing_course: "Purchasing course..." creating_class: "課堂創建中···"
# buy_course: "Buy Course" purchasing_course: "購買課程中···"
# buy_course1: "Buy this course" buy_course: "購買課程"
# create_class: "Create Class" buy_course1: "購買這個課程"
# select_all_courses: "Select 'All Courses' for a 50% discount!" create_class: "創建課堂"
# all_courses: "All Courses" select_all_courses: "可半價一次購買所有課程!"
# number_students: "Number of students" all_courses: "所有課程"
# enter_number_students: "Enter the number of students you need for this class." number_students: "學生人數"
# name_class: "Name your class" enter_number_students: "輪入該課堂的學生上限人數"
# displayed_course_page: "This will be displayed on the course page for you and your students. It can be changed later." name_class: "命名您的課堂"
# buy: "Buy" displayed_course_page: "這將會在課程頁面顯示,可被修改。"
# purchasing_for: "You are purchasing a license for" buy: "購買"
# creating_for: "You are creating a class for" purchasing_for: "你正在購買許可證,課程為"
# for: "for" # Like in 'for 30 students' creating_for: "您正在創建一個課程為"
# receive_code: "Afterwards you will receive an unlock code to distribute to your students, which they can use to enroll in your class." for: ",人數上限為" # Like in 'for 30 students'
# free_trial: "Free trial for teachers!" receive_code: "然後您會收到一個解鎖碼,把它分發給你的學生用來註冊你的課堂。"
# get_access: "to get individual access to all courses for evalutaion purposes." free_trial: "老師可免費試用!"
# questions: "Questions?" get_access: "獲得個人使用權在評估目的下來使用所有課程。"
# faq: "Courses FAQ" questions: "有疑問?"
# question: "Q:" # Like in 'Question' faq: "課程FAQ"
# question1: "What's the difference between these courses and the single player game?" question: "問:" # Like in 'Question'
# answer: "A:" # Like in 'Answer' question1: "這些課程和單人遊戲之間的有什麼區別?"
# answer1: "The single player game is designed for individuals, while the courses are designed for classes." answer: "答:" # Like in 'Answer'
# answer2: "The single player game has items, gems, hero selection, leveling up, and in-app purchases. Courses have classroom management features and streamlined student-focused level pacing." answer1: "單人遊戲是專為個人而設,而課程是專為課堂而設。"
# teachers_click: "Teachers Click Here" answer2: "在單人遊戲中有物品、寶石、英雄選擇、練級、和內購應用。課程有課堂管理功能,和老師可根據學生的水平而調整教學進度。"
# students_click: "Students Click Here" teachers_click: "老師點擊這裡"
# courses_on_coco: "Courses on CodeCombat" students_click: "學生點擊這裡"
# designed_to: "Courses are designed to introduce computer science concepts using CodeCombat's fun and engaging environment. CodeCombat levels are organized around key topics to encourage progressive learning, over the course of 5 hours." courses_on_coco: "CodeCombat上的課程"
# more_in_less: "Learn more in less time" designed_to: "CodeCombat課程的宗旨是在使用CodeCombat生動有趣的環境下教授計算機科學的課目。整個CodeCombat的關卡是圍繞著計算機科學的重點並激勵學生們自主向上學習在5小時的過程。"
# no_experience: "No coding experience necesssary" more_in_less: "以最少的時間學習最多的知識"
# easy_monitor: "Easily monitor student progress" no_experience: "無需編程經驗"
# purchase_for_class: "Purchase a course for your entire class. It's easy to sign up your students!" easy_monitor: "容易管理學生的進程"
# see_the: "See the" purchase_for_class: "為你的班級購買CodeCombat課程讓簽到和管理變得更容易"
# more_info: "for more information." see_the: "詳細資訊請看"
# choose_course: "Choose Your Course:" more_info: ""
# enter_code: "Enter an unlock code" choose_course: "選擇您的課程:"
# enter_code1: "Enter unlock code" enter_code: "輸入一個解銷碼"
# enroll: "Enroll" enter_code1: "輸入解銷碼"
# pick_from_classes: "Pick from your current classes" enroll: "註冊"
# enter: "Enter" pick_from_classes: "從目前的課程選擇"
# or: "Or" enter: "輪入"
# topics: "Topics" or: ""
# hours_content: "Hours of content:" topics: "題目"
# get_free: "Get FREE course" hours_content: "內容時間:"
get_free: "取得免費課程!"
classes: classes:
archmage_title: "大法師" archmage_title: "大法師"
@ -1207,7 +1208,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
recently_played: "最近玩過" recently_played: "最近玩過"
no_recent_games: "在過去兩個星期沒有玩過遊戲。" no_recent_games: "在過去兩個星期沒有玩過遊戲。"
payments: "付款" payments: "付款"
# prepaid: "Prepaid" prepaid: "充值"
purchased: "已購買" purchased: "已購買"
sale: "促銷" sale: "促銷"
subscription: "訂閱" subscription: "訂閱"
@ -1238,13 +1239,13 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
retrying: "服務器錯誤,重試中。" retrying: "服務器錯誤,重試中。"
success: "支付成功。謝謝!" success: "支付成功。謝謝!"
# account_prepaid: account_prepaid:
# purchase_code: "Purchase a Subscription Code" purchase_code: "購買訂閱碼"
# purchase_amount: "Amount" purchase_amount: "數量"
# purchase_total: "Total" purchase_total: "總共"
# purchase_button: "Submit Purchase" purchase_button: "提交購買"
# your_codes: "Your Codes:" your_codes: "你的訂閱碼:"
# redeem_codes: "Redeem a Subscription Code" redeem_codes: "兌換訂閱碼"
loading_error: loading_error:
could_not_load: "從伺服器載入失敗" could_not_load: "從伺服器載入失敗"
@ -1258,7 +1259,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
bad_input: "錯誤輸入。" bad_input: "錯誤輸入。"
server_error: "伺服器錯誤。" server_error: "伺服器錯誤。"
unknown: "未知錯誤。" unknown: "未知錯誤。"
# error: "ERROR" error: "錯誤"
resources: resources:
sessions: "會話" sessions: "會話"

View file

@ -25,9 +25,6 @@
margin-bottom: 20px margin-bottom: 20px
font-size: 14pt font-size: 14pt
.btn-enroll
margin-top: 20px
.center .center
text-align: center text-align: center

View file

@ -15,24 +15,54 @@ block content
if state === 'unknown_error' if state === 'unknown_error'
.alert.alert-danger.alert-dismissible= stateMessage .alert.alert-danger.alert-dismissible= stateMessage
if studentMode if hocLandingPage
+student-main +hoc-landing
else else
+teacher-main if studentMode
.container-fluid +student-main
- var i = 0 else
while i < courses.length if hocMode
.row +teacher-hoc
+course-block(courses[i], instances) else
- i++ +teacher-main
if i < courses.length .container-fluid
- var i = 0
while i < courses.length
.row
+course-block(courses[i], instances) +course-block(courses[i], instances)
- i++ - i++
if i < courses.length
+course-block(courses[i], instances)
- i++
mixin hoc-landing
h1.center Welcome Hour of Code!
br
.container-fluid
.row
.col-md-6.center
button.btn.btn-lg.btn-success.btn-student(data-i18n="courses.students_click")
.col-md-6.center
button.btn.btn-lg.btn-default.btn-teacher(data-i18n="courses.teachers_click")
mixin student-main mixin student-main
button.btn.btn-warning.btn-teacher(data-i18n="courses.teachers_click") button.btn.btn-warning.btn-teacher(data-i18n="courses.teachers_click")
h1.center(data-i18n="courses.courses_on_coco") h1.center(data-i18n="courses.courses_on_coco")
mixin teacher-hoc
button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
h1.center Welcome Hour of Code!
p
strong How to use CodeCombat with your students:
ol
li Click the green 'Get FREE course' button below
li Follow the enrollment instructions
li Add students via the 'Add Students' tab
p
span.spr If you have any problems, please email
a(href='mailto:team@codecombat.com') team@codecombat.com
br
mixin teacher-main mixin teacher-main
button.btn.btn-warning.btn-student(data-i18n="courses.students_click") button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
h1.center(data-i18n="courses.courses_on_coco") h1.center(data-i18n="courses.courses_on_coco")
@ -87,6 +117,14 @@ mixin student-dialog(course)
input.code-input(type='text', data-course-id="#{course.id}", data-i18n="[placeholder]courses.enter_code1", placeholder="Enter unlock code") input.code-input(type='text', data-course-id="#{course.id}", data-i18n="[placeholder]courses.enter_code1", placeholder="Enter unlock code")
.col-md-4 .col-md-4
button.btn.btn-success.btn-enroll(data-course-id="#{course.id}", data-i18n="courses.enroll") button.btn.btn-success.btn-enroll(data-course-id="#{course.id}", data-i18n="courses.enroll")
if hocMode && course.get('pricePerSeat') === 0
.row.button-row.center.row-pick-class
.col-md-12
br
div.or(data-i18n="courses.or")
.row.button-row.center
.col-md-12
button.btn.btn-success.btn-lg.btn-hoc-student-continue(data-course-id="#{course.id}") Continue by yourself
mixin teacher-dialog(course) mixin teacher-dialog(course)
.modal.continue-dialog(id="continueModal#{course.id}") .modal.continue-dialog(id="continueModal#{course.id}")

View file

@ -2,37 +2,24 @@ extends /templates/base
block content block content
h2(style='color:#CC0000;') Try CodeCombat Courses! h2 Hour of Code(Combat)
p p
strong What are CodeCombat Courses? strong Hi Teachers!
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 p
a.spr(href='/courses') Courses strong How to use CodeCombat with your students:
span organize the same great levels into groups. They make it easier for you to manage a class of students and monitor their progress.
p
strong How to use them:
ol ol
li li
span.spr Navigate to the span.spr Navigate to the
a.spr(href='/courses') Courses a.spr(href='/courses/teachers?hoc=true') Courses
span page span page
li Click the green 'Get FREE course' button 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
strong We Need Your Help! span.spr If you have any problems, please email
p Courses are still in early development, and we need your feedback to make them great for the classroom.
p
strong How you can help:
ul
li
spa.spr Spend 5 minutes checking out
a.spr(href='/courses') Courses
li Enroll in a course and add a student
li Monitor a group of students working through the first course
p
span.spr Send your feedback to
a(href='mailto:team@codecombat.com') team@codecombat.com a(href='mailto:team@codecombat.com') team@codecombat.com
p Thanks!
br br
h2 More Info for Teachers h2 More Info for Teachers

View file

@ -37,10 +37,7 @@ module.exports = class PrepaidView extends RootView
@updateTotal() @updateTotal()
@codes = new CocoCollection([], { url: '/db/user/'+me.id+'/prepaid_codes', model: Prepaid }) @codes = new CocoCollection([], { url: '/db/user/'+me.id+'/prepaid_codes', model: Prepaid })
@codes.on 'add', (code) => @codes.on 'sync', (code) => @render?()
@render?()
@codes.on 'sync', (code) =>
@render?()
@supermodel.loadCollection(@codes, 'prepaid', {cache: false}) @supermodel.loadCollection(@codes, 'prepaid', {cache: false})
@ppc = utils.getQueryVariable('_ppc') ? '' @ppc = utils.getQueryVariable('_ppc') ? ''

View file

@ -30,7 +30,7 @@ module.exports = class TrialRequestsView extends RootView
-1 -1
else else
1 1
@trialRequests = new CocoCollection([], { url: '/db/trial.request', model: TrialRequest, comparator: sortRequests }) @trialRequests = new CocoCollection([], { url: '/db/trial.request?conditions[sort]=-_id&conditions[limit]=500', model: TrialRequest, comparator: sortRequests })
@supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false}) @supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false})
getRenderData: -> getRenderData: ->

View file

@ -7,6 +7,8 @@ RootView = require 'views/core/RootView'
template = require 'templates/courses/courses' template = require 'templates/courses/courses'
utils = require 'core/utils' utils = require 'core/utils'
# TODO: Hour of Code (HoC) integration is a mess
module.exports = class CoursesView extends RootView module.exports = class CoursesView extends RootView
id: 'courses-view' id: 'courses-view'
template: template template: template
@ -15,12 +17,15 @@ module.exports = class CoursesView extends RootView
'click .btn-buy': 'onClickBuy' 'click .btn-buy': 'onClickBuy'
'click .btn-enroll': 'onClickEnroll' 'click .btn-enroll': 'onClickEnroll'
'click .btn-enter': 'onClickEnter' 'click .btn-enter': 'onClickEnter'
'click .btn-hoc-student-continue': 'onClickHocStudentContinue'
'click .btn-student': 'onClickStudent' 'click .btn-student': 'onClickStudent'
'click .btn-teacher': 'onClickTeacher' 'click .btn-teacher': 'onClickTeacher'
constructor: (options) -> constructor: (options) ->
super(options) super(options)
@praise = utils.getCoursePraise() @praise = utils.getCoursePraise()
@hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
@hocMode = utils.getQueryVariable('hoc', false)
@studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0 @studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0
@courses = new CocoCollection([], { url: "/db/course", model: Course}) @courses = new CocoCollection([], { url: "/db/course", model: Course})
@supermodel.loadCollection(@courses, 'courses') @supermodel.loadCollection(@courses, 'courses')
@ -38,6 +43,8 @@ module.exports = class CoursesView extends RootView
context = super() context = super()
context.courses = @courses.models ? [] context.courses = @courses.models ? []
context.enrolledCourses = @enrolledCourses ? {} context.enrolledCourses = @enrolledCourses ? {}
context.hocLandingPage = @hocLandingPage
context.hocMode = @hocMode
context.instances = @courseInstances.models ? [] context.instances = @courseInstances.models ? []
context.praise = @praise context.praise = @praise
context.state = @state context.state = @state
@ -95,14 +102,58 @@ module.exports = class CoursesView extends RootView
navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs
Backbone.Mediator.publish 'router:navigate', navigationEvent Backbone.Mediator.publish 'router:navigate', navigationEvent
onClickHocStudentContinue: (e) ->
$('.continue-dialog').modal('hide')
return @openModalView new AuthModal() if me.isAnonymous()
courseID = $(e.target).data('course-id')
@state = 'enrolling'
@stateMessage = undefined
@render?()
# TODO: Copied from CourseEnrollView
data =
name: 'Single Player'
seats: 9999
courseID: courseID
jqxhr = $.post('/db/course_instance/-/create', data)
jqxhr.done (data, textStatus, jqXHR) =>
application.tracker?.trackEvent 'Finished HoC student course creation', {courseID: courseID}
# TODO: handle fetch errors
me.fetch(cache: false).always =>
courseID = courseID
route = "/courses/#{courseID}"
viewArgs = [{}, courseID]
if data?.length > 0
courseInstanceID = data[0]._id
route += "/#{courseInstanceID}"
viewArgs[0].courseInstanceID = courseInstanceID
Backbone.Mediator.publish 'router:navigate',
route: route
viewClass: 'views/courses/CourseDetailsView'
viewArgs: viewArgs
jqxhr.fail (xhr, textStatus, errorThrown) =>
console.error 'Got an error purchasing a course:', textStatus, errorThrown
application.tracker?.trackEvent 'Failed HoC student course creation', status: textStatus
if xhr.status is 402
@state = 'declined'
@stateMessage = arguments[2]
else
@state = 'unknown_error'
@stateMessage = "#{xhr.status}: #{xhr.responseText}"
@render?()
onClickStudent: (e) -> onClickStudent: (e) ->
route = "/courses/students" route = "/courses/students"
route += "?hoc=true" if @hocLandingPage or @hocMode
viewClass = require 'views/courses/CoursesView' viewClass = require 'views/courses/CoursesView'
navigationEvent = route: route, viewClass: viewClass, viewArgs: [] navigationEvent = route: route, viewClass: viewClass, viewArgs: []
Backbone.Mediator.publish 'router:navigate', navigationEvent Backbone.Mediator.publish 'router:navigate', navigationEvent
onClickTeacher: (e) -> onClickTeacher: (e) ->
route = "/courses/teachers" route = "/courses/teachers"
route += "?hoc=true" if @hocLandingPage or @hocMode
viewClass = require 'views/courses/CoursesView' viewClass = require 'views/courses/CoursesView'
navigationEvent = route: route, viewClass: viewClass, viewArgs: [] navigationEvent = route: route, viewClass: viewClass, viewArgs: []
Backbone.Mediator.publish 'router:navigate', navigationEvent Backbone.Mediator.publish 'router:navigate', navigationEvent

View file

@ -179,21 +179,18 @@ module.exports = class Handler
# if it's not a text search but the user is an admin, let him try stuff anyway # if it's not a text search but the user is an admin, let him try stuff anyway
else if req.user?.isAdmin() else if req.user?.isAdmin()
# admins can send any sort of query down the wire # admins can send any sort of query down the wire
# Example URL: http://localhost:3000/db/user?filter[anonymous]=true
filter = {} filter = {}
filter[key] = (val for own key, val of req.query.filter when key not in specialParameters) if 'filter' of req.query filter[key] = JSON.parse(val) for own key, val of req.query.filter when key not in specialParameters if 'filter' of req.query
query = @modelClass.find(filter) query = @modelClass.find(filter)
# Conditions are chained query functions, for example: query.find().limit(20).sort('-dateCreated') # Conditions are chained query functions, for example: query.find().limit(20).sort('-dateCreated')
conditions = JSON.parse(req.query.conditions || '[]') # Example URL: http://localhost:3000/db/user?conditions[limit]=20&conditions[sort]=-dateCreated
hasLimit = false hasLimit = false
try try
for condition in conditions for own key, val of req.query.conditions
name = condition[0] query = query[key](val)
f = query[name] hasLimit ||= key is 'limit'
args = condition[1..]
query = query[name](args...)
hasLimit ||= f is 'limit'
catch e catch e
return @sendError(res, 422, 'Badly formed conditions.') return @sendError(res, 422, 'Badly formed conditions.')
query.limit(2000) unless hasLimit query.limit(2000) unless hasLimit

View file

@ -53,7 +53,6 @@ config.mail =
username: process.env.COCO_MAIL_SERVICE_USERNAME or '' username: process.env.COCO_MAIL_SERVICE_USERNAME or ''
supportPrimary: process.env.COCO_MAIL_SUPPORT_PRIMARY or '' supportPrimary: process.env.COCO_MAIL_SUPPORT_PRIMARY or ''
supportPremium: process.env.COCO_MAIL_SUPPORT_PREMIUM or '' supportPremium: process.env.COCO_MAIL_SUPPORT_PREMIUM or ''
username: process.env.COCO_MAIL_SERVICE_USERNAME or ''
mailchimpAPIKey: process.env.COCO_MAILCHIMP_API_KEY or '' mailchimpAPIKey: process.env.COCO_MAILCHIMP_API_KEY or ''
mailchimpWebhook: process.env.COCO_MAILCHIMP_WEBHOOK or '/mail/webhook' mailchimpWebhook: process.env.COCO_MAILCHIMP_WEBHOOK or '/mail/webhook'
sendwithusAPIKey: process.env.COCO_SENDWITHUS_API_KEY or '' sendwithusAPIKey: process.env.COCO_SENDWITHUS_API_KEY or ''

View file

@ -86,7 +86,6 @@ setupCountryRedirectMiddleware = (app, country="china", countryCode="CN", langua
ip = req.headers['x-forwarded-for'] or req.connection.remoteAddress ip = req.headers['x-forwarded-for'] or req.connection.remoteAddress
ip = ip?.split(/,? /)[0] # If there are two IP addresses, say because of CloudFlare, we just take the first. ip = ip?.split(/,? /)[0] # If there are two IP addresses, say because of CloudFlare, we just take the first.
geo = geoip.lookup(ip) geo = geoip.lookup(ip)
geo = country: 'CN'
#if speaksLanguage or geo?.country is countryCode #if speaksLanguage or geo?.country is countryCode
# log.info("Should we redirect to #{serverID} server? speaksLanguage: #{speaksLanguage}, firstLanguage: #{firstLanguage}, ip: #{ip}, geo: #{geo} -- so redirecting? #{geo?.country is 'CN' and speaksLanguage}") # log.info("Should we redirect to #{serverID} server? speaksLanguage: #{speaksLanguage}, firstLanguage: #{firstLanguage}, ip: #{ip}, geo: #{geo} -- so redirecting? #{geo?.country is 'CN' and speaksLanguage}")
return geo?.country is countryCode and speaksLanguage return geo?.country is countryCode and speaksLanguage

View file

@ -269,20 +269,10 @@ describe 'GET /db/user', ->
expect(body.type).toBeDefined() expect(body.type).toBeDefined()
done() done()
it 'is able to do a sweet query', (done) -> it 'is able to do a semi-sweet query', (done) ->
conditions = [
['limit', 20]
['where', 'email']
['equals', 'admin@afc.com']
['sort', '-dateCreated']
]
options = { options = {
url: getURL(urlUser) url: getURL(urlUser) + "?conditions[limit]=20&conditions[sort]=-dateCreated"
qs: {
conditions: JSON.stringify(conditions)
}
} }
req = request.get(options, (error, response) -> req = request.get(options, (error, response) ->
expect(response.statusCode).toBe(200) expect(response.statusCode).toBe(200)
res = JSON.parse(response.body) res = JSON.parse(response.body)
@ -291,14 +281,8 @@ describe 'GET /db/user', ->
) )
it 'rejects bad conditions', (done) -> it 'rejects bad conditions', (done) ->
conditions = [
['lime', 20]
]
options = { options = {
url: getURL(urlUser) url: getURL(urlUser) + "?conditions[lime]=20&conditions[sort]=-dateCreated"
qs: {
conditions: JSON.stringify(conditions)
}
} }
req = request.get(options, (error, response) -> req = request.get(options, (error, response) ->