mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-13 09:11:22 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
70c139a600
16 changed files with 79 additions and 50 deletions
|
@ -71,6 +71,8 @@ module.exports = class TeacherClassView extends RootView
|
||||||
@singleStudentLevelProgressDotTemplate = require 'templates/teachers/hovers/progress-dot-single-student-level'
|
@singleStudentLevelProgressDotTemplate = require 'templates/teachers/hovers/progress-dot-single-student-level'
|
||||||
@allStudentsLevelProgressDotTemplate = require 'templates/teachers/hovers/progress-dot-all-students-single-level'
|
@allStudentsLevelProgressDotTemplate = require 'templates/teachers/hovers/progress-dot-all-students-single-level'
|
||||||
|
|
||||||
|
@debouncedRender = _.debounce @render
|
||||||
|
|
||||||
@state = new State(@getInitialState())
|
@state = new State(@getInitialState())
|
||||||
@updateHash @state.get('activeTab') # TODO: Don't push to URL history (maybe don't use url fragment for default tab)
|
@updateHash @state.get('activeTab') # TODO: Don't push to URL history (maybe don't use url fragment for default tab)
|
||||||
|
|
||||||
|
@ -120,11 +122,6 @@ module.exports = class TeacherClassView extends RootView
|
||||||
@attachMediatorEvents()
|
@attachMediatorEvents()
|
||||||
|
|
||||||
attachMediatorEvents: () ->
|
attachMediatorEvents: () ->
|
||||||
@listenTo @state, 'sync change', ->
|
|
||||||
if _.isEmpty(_.omit(@state.changed, 'searchTerm'))
|
|
||||||
@renderSelectors('#enrollment-status-table')
|
|
||||||
else
|
|
||||||
@render()
|
|
||||||
# Model/Collection events
|
# Model/Collection events
|
||||||
@listenTo @classroom, 'sync change update', ->
|
@listenTo @classroom, 'sync change update', ->
|
||||||
classCode = @classroom.get('codeCamel') or @classroom.get('code')
|
classCode = @classroom.get('codeCamel') or @classroom.get('code')
|
||||||
|
@ -137,7 +134,6 @@ module.exports = class TeacherClassView extends RootView
|
||||||
@state.set selectedCourse: @courses.first() unless @state.get('selectedCourse')
|
@state.set selectedCourse: @courses.first() unless @state.get('selectedCourse')
|
||||||
@listenTo @courseInstances, 'sync change update', ->
|
@listenTo @courseInstances, 'sync change update', ->
|
||||||
@setCourseMembers()
|
@setCourseMembers()
|
||||||
@render() # TODO: use state
|
|
||||||
@listenTo @courseInstances, 'add-members', ->
|
@listenTo @courseInstances, 'add-members', ->
|
||||||
noty text: $.i18n.t('teacher.assigned'), layout: 'center', type: 'information', killer: true, timeout: 5000
|
noty text: $.i18n.t('teacher.assigned'), layout: 'center', type: 'information', killer: true, timeout: 5000
|
||||||
@listenTo @students, 'sync change update add remove reset', ->
|
@listenTo @students, 'sync change update add remove reset', ->
|
||||||
|
@ -149,7 +145,6 @@ module.exports = class TeacherClassView extends RootView
|
||||||
@state.set students: @students
|
@state.set students: @students
|
||||||
@listenTo @students, 'sort', ->
|
@listenTo @students, 'sort', ->
|
||||||
@state.set students: @students
|
@state.set students: @students
|
||||||
@render()
|
|
||||||
@listenTo @, 'course-select:change', ({ selectedCourse }) ->
|
@listenTo @, 'course-select:change', ({ selectedCourse }) ->
|
||||||
@state.set selectedCourse: selectedCourse
|
@state.set selectedCourse: selectedCourse
|
||||||
|
|
||||||
|
@ -162,6 +157,15 @@ module.exports = class TeacherClassView extends RootView
|
||||||
onLoaded: ->
|
onLoaded: ->
|
||||||
@removeDeletedStudents() # TODO: Move this to mediator listeners? For both classroom and students?
|
@removeDeletedStudents() # TODO: Move this to mediator listeners? For both classroom and students?
|
||||||
@calculateProgressAndLevels()
|
@calculateProgressAndLevels()
|
||||||
|
|
||||||
|
# render callback setup
|
||||||
|
@listenTo @courseInstances, 'sync change update', @debouncedRender
|
||||||
|
@listenTo @state, 'sync change', ->
|
||||||
|
if _.isEmpty(_.omit(@state.changed, 'searchTerm'))
|
||||||
|
@renderSelectors('#enrollment-status-table')
|
||||||
|
else
|
||||||
|
@debouncedRender()
|
||||||
|
@listenTo @students, 'sort', @debouncedRender
|
||||||
super()
|
super()
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
|
|
@ -260,7 +260,10 @@ module.exports.ThangTypeNode = ThangTypeNode = class ThangTypeNode extends Treem
|
||||||
thangType?.name or '...'
|
thangType?.name or '...'
|
||||||
|
|
||||||
getThangTypes: ->
|
getThangTypes: ->
|
||||||
return if ThangTypeNode.thangTypesCollection
|
if ThangTypeNode.thangTypesCollection
|
||||||
|
if not @constructor.thangTypes
|
||||||
|
@processThangTypes(ThangTypeNode.thangTypesCollection)
|
||||||
|
return
|
||||||
ThangTypeNode.thangTypesCollection = new CocoCollection([], {
|
ThangTypeNode.thangTypesCollection = new CocoCollection([], {
|
||||||
url: '/db/thang.type'
|
url: '/db/thang.type'
|
||||||
project:['name', 'components', 'original']
|
project:['name', 'components', 'original']
|
||||||
|
|
|
@ -91,7 +91,8 @@ emailUserInitialRecruiting = (user, callback) ->
|
||||||
team = user.session.levelInfo.team
|
team = user.session.levelInfo.team
|
||||||
team = team.substr(0, team.length - 1)
|
team = team.substr(0, team.length - 1)
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.recruiting_email
|
email_id: sendwithus.templates.recruiting_email.id
|
||||||
|
version_name: sendwithus.templates.recruiting_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: if DEBUGGING then 'nick@codecombat.com' else user.email
|
address: if DEBUGGING then 'nick@codecombat.com' else user.email
|
||||||
name: name
|
name: name
|
||||||
|
@ -134,7 +135,8 @@ emailUserTournamentResults = (winner, callback) ->
|
||||||
name = winner.name
|
name = winner.name
|
||||||
team = winner.team.substr(0, winner.team.length - 1)
|
team = winner.team.substr(0, winner.team.length - 1)
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.greed_tournament_rank
|
email_id: sendwithus.templates.greed_tournament_rank.id
|
||||||
|
version_name: sendwithus.templates.greed_tournament_rank.version
|
||||||
recipient:
|
recipient:
|
||||||
address: if DEBUGGING then 'nick@codecombat.com' else winner.email
|
address: if DEBUGGING then 'nick@codecombat.com' else winner.email
|
||||||
name: name
|
name: name
|
||||||
|
|
|
@ -107,6 +107,7 @@ function upsertLeads(done) {
|
||||||
function getCountryCode(country, emails) {
|
function getCountryCode(country, emails) {
|
||||||
// console.log(`DEBUG: getCountryCode ${country} ${emails.length}`);
|
// console.log(`DEBUG: getCountryCode ${country} ${emails.length}`);
|
||||||
if (country) {
|
if (country) {
|
||||||
|
if (country.indexOf('Nederland') >= 0) return 'NL';
|
||||||
let countryCode = countryList.getCode(country);
|
let countryCode = countryList.getCode(country);
|
||||||
if (countryCode) return countryCode;
|
if (countryCode) return countryCode;
|
||||||
}
|
}
|
||||||
|
@ -728,7 +729,7 @@ function createUpdateLeadFn(lead, existingLeads) {
|
||||||
if (data.total_results === 0) {
|
if (data.total_results === 0) {
|
||||||
if (existingLeads[lead.name.toLowerCase()]) {
|
if (existingLeads[lead.name.toLowerCase()]) {
|
||||||
if (existingLeads[lead.name.toLowerCase()].length === 1) {
|
if (existingLeads[lead.name.toLowerCase()].length === 1) {
|
||||||
console.log(`DEBUG: Using lead from email lookup: ${lead.name}`);
|
// console.log(`DEBUG: Using lead from email lookup: ${lead.name}`);
|
||||||
return updateExistingLead(lead, existingLeads[lead.name.toLowerCase()][0], done);
|
return updateExistingLead(lead, existingLeads[lead.name.toLowerCase()][0], done);
|
||||||
}
|
}
|
||||||
console.error(`ERROR: ${existingLeads[lead.name.toLowerCase()].length} email leads found for ${lead.name}`);
|
console.error(`ERROR: ${existingLeads[lead.name.toLowerCase()].length} email leads found for ${lead.name}`);
|
||||||
|
|
|
@ -468,7 +468,8 @@ module.exports = class Handler
|
||||||
|
|
||||||
notifyWatcherOfChange: (editor, watcher, changedDocument, editPath) ->
|
notifyWatcherOfChange: (editor, watcher, changedDocument, editPath) ->
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.change_made_notify_watcher
|
email_id: sendwithus.templates.change_made_notify_watcher.id
|
||||||
|
version_name: sendwithus.templates.change_made_notify_watcher.version
|
||||||
recipient:
|
recipient:
|
||||||
address: watcher.get('email')
|
address: watcher.get('email')
|
||||||
name: watcher.get('name')
|
name: watcher.get('name')
|
||||||
|
|
|
@ -187,7 +187,8 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
||||||
return @sendForbiddenError(res) unless prepaid.get('maxRedeemers') > prepaid.get('redeemers').length
|
return @sendForbiddenError(res) unless prepaid.get('maxRedeemers') > prepaid.get('redeemers').length
|
||||||
for email in req.body.emails
|
for email in req.body.emails
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.course_invite_email
|
email_id: sendwithus.templates.course_invite_email.id
|
||||||
|
version: sendwithus.templates.course_invite_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: email
|
address: email
|
||||||
subject: course.get('name')
|
subject: course.get('name')
|
||||||
|
|
|
@ -100,7 +100,8 @@ PatchHandler = class PatchHandler extends Handler
|
||||||
sendPatchCreatedEmail: (patchCreator, watcher, patch, target, docLink) ->
|
sendPatchCreatedEmail: (patchCreator, watcher, patch, target, docLink) ->
|
||||||
# return if watcher._id is patchCreator._id
|
# return if watcher._id is patchCreator._id
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.patch_created
|
email_id: sendwithus.templates.patch_created.id
|
||||||
|
version_name: sendwithus.templates.patch_created.version
|
||||||
recipient:
|
recipient:
|
||||||
address: watcher.get('email')
|
address: watcher.get('email')
|
||||||
name: watcher.get('name')
|
name: watcher.get('name')
|
||||||
|
|
|
@ -132,7 +132,8 @@ module.exports =
|
||||||
user.set('passwordReset', utils.getCodeCamel())
|
user.set('passwordReset', utils.getCodeCamel())
|
||||||
yield user.save()
|
yield user.save()
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.password_reset
|
email_id: sendwithus.templates.password_reset.id
|
||||||
|
version_name: sendwithus.templates.password_reset.version
|
||||||
recipient:
|
recipient:
|
||||||
address: req.body.email
|
address: req.body.email
|
||||||
email_data:
|
email_data:
|
||||||
|
|
|
@ -235,7 +235,8 @@ module.exports =
|
||||||
for email in req.body.emails
|
for email in req.body.emails
|
||||||
joinCode = (classroom.get('codeCamel') or classroom.get('code'))
|
joinCode = (classroom.get('codeCamel') or classroom.get('code'))
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.course_invite_email
|
email_id: sendwithus.templates.course_invite_email.id
|
||||||
|
version_name: sendwithus.templates.course_invite_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: email
|
address: email
|
||||||
email_data:
|
email_data:
|
||||||
|
|
|
@ -85,7 +85,8 @@ module.exports =
|
||||||
if not user
|
if not user
|
||||||
throw new errors.NotFound('User not found')
|
throw new errors.NotFound('User not found')
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.verify_email
|
email_id: sendwithus.templates.verify_email.id
|
||||||
|
version_name: sendwithus.templates.verify_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: user.get('email')
|
address: user.get('email')
|
||||||
name: user.broadName()
|
name: user.broadName()
|
||||||
|
|
|
@ -107,7 +107,8 @@ module.exports =
|
||||||
User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) ->
|
User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) ->
|
||||||
for watcher in watchers
|
for watcher in watchers
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.change_made_notify_watcher
|
email_id: sendwithus.templates.change_made_notify_watcher.id
|
||||||
|
version_name: sendwithus.templates.change_made_notify_watcher.version
|
||||||
recipient:
|
recipient:
|
||||||
address: watcher.get('email')
|
address: watcher.get('email')
|
||||||
name: watcher.get('name')
|
name: watcher.get('name')
|
||||||
|
|
|
@ -61,7 +61,8 @@ createSendWithUsContext = (req, fromAddress, subject, content, done) ->
|
||||||
else config.mail.supportPrimary
|
else config.mail.supportPrimary
|
||||||
|
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.plain_text_email
|
email_id: sendwithus.templates.plain_text_email.id
|
||||||
|
version_name: sendwithus.templates.plain_text_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: toAddress
|
address: toAddress
|
||||||
sender:
|
sender:
|
||||||
|
|
|
@ -592,7 +592,8 @@ sendLadderUpdateEmail = (session, now, daysAgo) ->
|
||||||
sendEmail = (defeatContext, victoryContext, levelVersionsContext) ->
|
sendEmail = (defeatContext, victoryContext, levelVersionsContext) ->
|
||||||
# TODO: do something with the preferredLanguage?
|
# TODO: do something with the preferredLanguage?
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.ladder_update_email
|
email_id: sendwithus.templates.ladder_update_email.id
|
||||||
|
version_name: sendwithus.templates.ladder_update_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: if DEBUGGING then 'nick@codecombat.com' else user.get('email')
|
address: if DEBUGGING then 'nick@codecombat.com' else user.get('email')
|
||||||
name: name
|
name: name
|
||||||
|
@ -721,7 +722,8 @@ sendNextStepsEmail = (user, now, daysAgo) ->
|
||||||
# Used to use these categories to customize the email; not doing it right now. TODO: customize it again in Sendwithus.
|
# Used to use these categories to customize the email; not doing it right now. TODO: customize it again in Sendwithus.
|
||||||
# TODO: do something with the preferredLanguage?
|
# TODO: do something with the preferredLanguage?
|
||||||
context =
|
context =
|
||||||
email_id: sendwithus.templates.next_steps_email
|
email_id: sendwithus.templates.next_steps_email.id
|
||||||
|
version_name: sendwithus.templates.next_steps_email.version
|
||||||
recipient:
|
recipient:
|
||||||
address: if DEBUGGING then 'nick@codecombat.com' else user.get('email')
|
address: if DEBUGGING then 'nick@codecombat.com' else user.get('email')
|
||||||
name: name
|
name: name
|
||||||
|
|
|
@ -15,22 +15,26 @@ module.exports.api =
|
||||||
if swuAPIKey
|
if swuAPIKey
|
||||||
module.exports.api = new sendwithusAPI swuAPIKey, debug
|
module.exports.api = new sendwithusAPI swuAPIKey, debug
|
||||||
|
|
||||||
|
# Version name can be supplied to tie a specific version to a deploy.
|
||||||
|
# That is most useful for testing templates with new data fields on staging.
|
||||||
|
# If it doesn't need to be synchronized to a deploy, you can just "publish"
|
||||||
|
# the new template version on SendWithUs (and leave this version blank)
|
||||||
module.exports.templates =
|
module.exports.templates =
|
||||||
parent_subscribe_email: 'tem_2APERafogvwKhmcnouigud'
|
parent_subscribe_email: { id: 'tem_2APERafogvwKhmcnouigud' }
|
||||||
share_progress_email: 'tem_VHE3ihhGmVa3727qds9zY8'
|
share_progress_email: { id: 'tem_VHE3ihhGmVa3727qds9zY8' }
|
||||||
welcome_email_user: 'tem_z7Xvj3mtWYk6ec6aW7RwFk'
|
welcome_email_user: { id: 'tem_z7Xvj3mtWYk6ec6aW7RwFk' }
|
||||||
welcome_email_student: 'tem_4WYPZNLzs5wawMF9qUJXUH'
|
welcome_email_student: { id: 'tem_4WYPZNLzs5wawMF9qUJXUH' }
|
||||||
verify_email: 'tem_zJee6uRsRmzqzktzneCkCn'
|
verify_email: { id: 'tem_zJee6uRsRmzqzktzneCkCn' }
|
||||||
ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'
|
ladder_update_email: { id: 'JzaZxf39A4cKMxpPZUfWy4' }
|
||||||
patch_created: 'tem_xhxuNosLALsizTNojBjNcL'
|
patch_created: { id: 'tem_xhxuNosLALsizTNojBjNcL' }
|
||||||
change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG'
|
change_made_notify_watcher: { id: 'tem_7KVkfmv9SZETb25dtHbUtG' }
|
||||||
recruiting_email: 'tem_mdFMgtcczHKYu94Jmq68j8'
|
recruiting_email: { id: 'tem_mdFMgtcczHKYu94Jmq68j8' }
|
||||||
greed_tournament_rank: 'tem_c4KYnk2TriEkkZx5NqqGLG'
|
greed_tournament_rank: { id: 'tem_c4KYnk2TriEkkZx5NqqGLG' }
|
||||||
generic_email: 'tem_JhRnQ4pvTS4KdQjYoZdbei'
|
generic_email: { id: 'tem_JhRnQ4pvTS4KdQjYoZdbei' }
|
||||||
plain_text_email: 'tem_85UvKDCCNPXsFckERTig6Y'
|
plain_text_email: { id: 'tem_85UvKDCCNPXsFckERTig6Y' }
|
||||||
next_steps_email: 'tem_RDHhTG5inXQi8pthyqWr5D'
|
next_steps_email: { id: 'tem_RDHhTG5inXQi8pthyqWr5D' }
|
||||||
course_invite_email: 'tem_ic2ZhPkpj8GBADFuyAp4bj'
|
course_invite_email: { id: 'tem_u6D2EFWYC5Ptk38bSykjsU', version: 'v3' }
|
||||||
teacher_free_trial: 'tem_R7d9Hpoba9SceQNiYSXBak'
|
teacher_free_trial: { id: 'tem_R7d9Hpoba9SceQNiYSXBak' }
|
||||||
teacher_free_trial_hoc: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc'
|
teacher_free_trial_hoc: { id: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc' }
|
||||||
teacher_request_demo: 'tem_cwG3HZjEyb6QE493hZuUra'
|
teacher_request_demo: { id: 'tem_cwG3HZjEyb6QE493hZuUra' }
|
||||||
password_reset: 'tem_wbQUMRtLY9xhec8BSCykLA'
|
password_reset: { id: 'tem_wbQUMRtLY9xhec8BSCykLA' }
|
||||||
|
|
|
@ -75,24 +75,29 @@ describe 'TeacherClassView', ->
|
||||||
# it "shows the classroom's join code"
|
# it "shows the classroom's join code"
|
||||||
|
|
||||||
describe 'the Students tab', ->
|
describe 'the Students tab', ->
|
||||||
beforeEach ->
|
beforeEach (done) ->
|
||||||
@view.state.set('activeTab', '#students-tab')
|
@view.state.set('activeTab', '#students-tab')
|
||||||
|
_.defer(done)
|
||||||
|
|
||||||
# it 'shows all of the students'
|
# it 'shows all of the students'
|
||||||
# it 'sorts correctly by Name'
|
# it 'sorts correctly by Name'
|
||||||
# it 'sorts correctly by Progress'
|
# it 'sorts correctly by Progress'
|
||||||
|
|
||||||
describe 'bulk-assign controls', ->
|
describe 'bulk-assign controls', ->
|
||||||
it 'shows alert when assigning course 2 to unenrolled students', ->
|
it 'shows alert when assigning course 2 to unenrolled students', (done) ->
|
||||||
expect(@view.$('.cant-assign-to-unenrolled').hasClass('visible')).toBe(false)
|
expect(@view.$('.cant-assign-to-unenrolled').hasClass('visible')).toBe(false)
|
||||||
@view.$('.student-row .checkbox-flat').click()
|
@view.$('.student-row .checkbox-flat').click()
|
||||||
@view.$('.assign-to-selected-students').click()
|
@view.$('.assign-to-selected-students').click()
|
||||||
expect(@view.$('.cant-assign-to-unenrolled').hasClass('visible')).toBe(true)
|
_.defer =>
|
||||||
|
expect(@view.$('.cant-assign-to-unenrolled').hasClass('visible')).toBe(true)
|
||||||
|
done()
|
||||||
|
|
||||||
it 'shows alert when assigning but no students are selected', ->
|
it 'shows alert when assigning but no students are selected', (done) ->
|
||||||
expect(@view.$('.no-students-selected').hasClass('visible')).toBe(false)
|
expect(@view.$('.no-students-selected').hasClass('visible')).toBe(false)
|
||||||
@view.$('.assign-to-selected-students').click()
|
@view.$('.assign-to-selected-students').click()
|
||||||
expect(@view.$('.no-students-selected').hasClass('visible')).toBe(true)
|
_.defer =>
|
||||||
|
expect(@view.$('.no-students-selected').hasClass('visible')).toBe(true)
|
||||||
|
done()
|
||||||
|
|
||||||
# describe 'the Course Progress tab', ->
|
# describe 'the Course Progress tab', ->
|
||||||
# it 'shows the correct Course Overview progress'
|
# it 'shows the correct Course Overview progress'
|
||||||
|
|
Loading…
Reference in a new issue