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'
|
||||
@allStudentsLevelProgressDotTemplate = require 'templates/teachers/hovers/progress-dot-all-students-single-level'
|
||||
|
||||
@debouncedRender = _.debounce @render
|
||||
|
||||
@state = new State(@getInitialState())
|
||||
@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: () ->
|
||||
@listenTo @state, 'sync change', ->
|
||||
if _.isEmpty(_.omit(@state.changed, 'searchTerm'))
|
||||
@renderSelectors('#enrollment-status-table')
|
||||
else
|
||||
@render()
|
||||
# Model/Collection events
|
||||
@listenTo @classroom, 'sync change update', ->
|
||||
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')
|
||||
@listenTo @courseInstances, 'sync change update', ->
|
||||
@setCourseMembers()
|
||||
@render() # TODO: use state
|
||||
@listenTo @courseInstances, 'add-members', ->
|
||||
noty text: $.i18n.t('teacher.assigned'), layout: 'center', type: 'information', killer: true, timeout: 5000
|
||||
@listenTo @students, 'sync change update add remove reset', ->
|
||||
|
@ -149,7 +145,6 @@ module.exports = class TeacherClassView extends RootView
|
|||
@state.set students: @students
|
||||
@listenTo @students, 'sort', ->
|
||||
@state.set students: @students
|
||||
@render()
|
||||
@listenTo @, 'course-select:change', ({ selectedCourse }) ->
|
||||
@state.set selectedCourse: selectedCourse
|
||||
|
||||
|
@ -162,6 +157,15 @@ module.exports = class TeacherClassView extends RootView
|
|||
onLoaded: ->
|
||||
@removeDeletedStudents() # TODO: Move this to mediator listeners? For both classroom and students?
|
||||
@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()
|
||||
|
||||
afterRender: ->
|
||||
|
|
|
@ -119,4 +119,4 @@ class SolutionsNode extends TreemaArrayNode
|
|||
succeeds: true
|
||||
})
|
||||
|
||||
@set('/', solutions)
|
||||
@set('/', solutions)
|
||||
|
|
|
@ -260,7 +260,10 @@ module.exports.ThangTypeNode = ThangTypeNode = class ThangTypeNode extends Treem
|
|||
thangType?.name or '...'
|
||||
|
||||
getThangTypes: ->
|
||||
return if ThangTypeNode.thangTypesCollection
|
||||
if ThangTypeNode.thangTypesCollection
|
||||
if not @constructor.thangTypes
|
||||
@processThangTypes(ThangTypeNode.thangTypesCollection)
|
||||
return
|
||||
ThangTypeNode.thangTypesCollection = new CocoCollection([], {
|
||||
url: '/db/thang.type'
|
||||
project:['name', 'components', 'original']
|
||||
|
|
|
@ -91,7 +91,8 @@ emailUserInitialRecruiting = (user, callback) ->
|
|||
team = user.session.levelInfo.team
|
||||
team = team.substr(0, team.length - 1)
|
||||
context =
|
||||
email_id: sendwithus.templates.recruiting_email
|
||||
email_id: sendwithus.templates.recruiting_email.id
|
||||
version_name: sendwithus.templates.recruiting_email.version
|
||||
recipient:
|
||||
address: if DEBUGGING then 'nick@codecombat.com' else user.email
|
||||
name: name
|
||||
|
@ -134,7 +135,8 @@ emailUserTournamentResults = (winner, callback) ->
|
|||
name = winner.name
|
||||
team = winner.team.substr(0, winner.team.length - 1)
|
||||
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:
|
||||
address: if DEBUGGING then 'nick@codecombat.com' else winner.email
|
||||
name: name
|
||||
|
|
|
@ -107,6 +107,7 @@ function upsertLeads(done) {
|
|||
function getCountryCode(country, emails) {
|
||||
// console.log(`DEBUG: getCountryCode ${country} ${emails.length}`);
|
||||
if (country) {
|
||||
if (country.indexOf('Nederland') >= 0) return 'NL';
|
||||
let countryCode = countryList.getCode(country);
|
||||
if (countryCode) return countryCode;
|
||||
}
|
||||
|
@ -728,7 +729,7 @@ function createUpdateLeadFn(lead, existingLeads) {
|
|||
if (data.total_results === 0) {
|
||||
if (existingLeads[lead.name.toLowerCase()]) {
|
||||
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);
|
||||
}
|
||||
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) ->
|
||||
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:
|
||||
address: watcher.get('email')
|
||||
name: watcher.get('name')
|
||||
|
|
|
@ -187,7 +187,8 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
return @sendForbiddenError(res) unless prepaid.get('maxRedeemers') > prepaid.get('redeemers').length
|
||||
for email in req.body.emails
|
||||
context =
|
||||
email_id: sendwithus.templates.course_invite_email
|
||||
email_id: sendwithus.templates.course_invite_email.id
|
||||
version: sendwithus.templates.course_invite_email.version
|
||||
recipient:
|
||||
address: email
|
||||
subject: course.get('name')
|
||||
|
|
|
@ -100,7 +100,8 @@ PatchHandler = class PatchHandler extends Handler
|
|||
sendPatchCreatedEmail: (patchCreator, watcher, patch, target, docLink) ->
|
||||
# return if watcher._id is patchCreator._id
|
||||
context =
|
||||
email_id: sendwithus.templates.patch_created
|
||||
email_id: sendwithus.templates.patch_created.id
|
||||
version_name: sendwithus.templates.patch_created.version
|
||||
recipient:
|
||||
address: watcher.get('email')
|
||||
name: watcher.get('name')
|
||||
|
|
|
@ -52,7 +52,7 @@ module.exports =
|
|||
yield req.logInAsync(user)
|
||||
|
||||
if req.query.callback
|
||||
res.jsonp(req.user.toObject({req, publicOnly: true}))
|
||||
res.jsonp(req.user.toObject({req, publicOnly: true}))
|
||||
else
|
||||
res.send(req.user.toObject({req, publicOnly: false}))
|
||||
res.end()
|
||||
|
@ -132,7 +132,8 @@ module.exports =
|
|||
user.set('passwordReset', utils.getCodeCamel())
|
||||
yield user.save()
|
||||
context =
|
||||
email_id: sendwithus.templates.password_reset
|
||||
email_id: sendwithus.templates.password_reset.id
|
||||
version_name: sendwithus.templates.password_reset.version
|
||||
recipient:
|
||||
address: req.body.email
|
||||
email_data:
|
||||
|
|
|
@ -235,7 +235,8 @@ module.exports =
|
|||
for email in req.body.emails
|
||||
joinCode = (classroom.get('codeCamel') or classroom.get('code'))
|
||||
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:
|
||||
address: email
|
||||
email_data:
|
||||
|
|
|
@ -85,7 +85,8 @@ module.exports =
|
|||
if not user
|
||||
throw new errors.NotFound('User not found')
|
||||
context =
|
||||
email_id: sendwithus.templates.verify_email
|
||||
email_id: sendwithus.templates.verify_email.id
|
||||
version_name: sendwithus.templates.verify_email.version
|
||||
recipient:
|
||||
address: user.get('email')
|
||||
name: user.broadName()
|
||||
|
|
|
@ -107,7 +107,8 @@ module.exports =
|
|||
User.find({_id:{$in:watchers}}).select({email:1, name:1}).exec (err, watchers) ->
|
||||
for watcher in watchers
|
||||
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:
|
||||
address: watcher.get('email')
|
||||
name: watcher.get('name')
|
||||
|
@ -127,7 +128,7 @@ module.exports =
|
|||
original = req.params.handle
|
||||
version = req.params.version
|
||||
if not database.isID(original)
|
||||
throw new errors.UnprocessableEntity('Invalid MongoDB id: '+original)
|
||||
throw new errors.UnprocessableEntity('Invalid MongoDB id: '+original)
|
||||
|
||||
query = { 'original': mongoose.Types.ObjectId(original) }
|
||||
if version?
|
||||
|
|
|
@ -17,7 +17,7 @@ module.exports.setup = (app) ->
|
|||
req.user.update({$set: { enrollmentRequestSent: true }}).exec(_.noop) if req.body.recipientID is 'schools@codecombat.com'
|
||||
closeIO.sendMail fromAddress, subject, content, (err) ->
|
||||
log.error "Error sending contact form email via Close.io: #{err.message or err}" if err
|
||||
else
|
||||
else
|
||||
createSendWithUsContext req, fromAddress, subject, content, (context) ->
|
||||
sendwithus.api.send context, (err, result) ->
|
||||
log.error "Error sending contact form email via sendwithus: #{err.message or err}" if err
|
||||
|
@ -61,7 +61,8 @@ createSendWithUsContext = (req, fromAddress, subject, content, done) ->
|
|||
else config.mail.supportPrimary
|
||||
|
||||
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:
|
||||
address: toAddress
|
||||
sender:
|
||||
|
|
|
@ -592,7 +592,8 @@ sendLadderUpdateEmail = (session, now, daysAgo) ->
|
|||
sendEmail = (defeatContext, victoryContext, levelVersionsContext) ->
|
||||
# TODO: do something with the preferredLanguage?
|
||||
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:
|
||||
address: if DEBUGGING then 'nick@codecombat.com' else user.get('email')
|
||||
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.
|
||||
# TODO: do something with the preferredLanguage?
|
||||
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:
|
||||
address: if DEBUGGING then 'nick@codecombat.com' else user.get('email')
|
||||
name: name
|
||||
|
|
|
@ -11,26 +11,30 @@ module.exports.api =
|
|||
send: (context, cb) ->
|
||||
log.debug('Tried to send email with context: ', JSON.stringify(context, null, ' '))
|
||||
setTimeout(cb, 10)
|
||||
|
||||
|
||||
if swuAPIKey
|
||||
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 =
|
||||
parent_subscribe_email: 'tem_2APERafogvwKhmcnouigud'
|
||||
share_progress_email: 'tem_VHE3ihhGmVa3727qds9zY8'
|
||||
welcome_email_user: 'tem_z7Xvj3mtWYk6ec6aW7RwFk'
|
||||
welcome_email_student: 'tem_4WYPZNLzs5wawMF9qUJXUH'
|
||||
verify_email: 'tem_zJee6uRsRmzqzktzneCkCn'
|
||||
ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'
|
||||
patch_created: 'tem_xhxuNosLALsizTNojBjNcL'
|
||||
change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG'
|
||||
recruiting_email: 'tem_mdFMgtcczHKYu94Jmq68j8'
|
||||
greed_tournament_rank: 'tem_c4KYnk2TriEkkZx5NqqGLG'
|
||||
generic_email: 'tem_JhRnQ4pvTS4KdQjYoZdbei'
|
||||
plain_text_email: 'tem_85UvKDCCNPXsFckERTig6Y'
|
||||
next_steps_email: 'tem_RDHhTG5inXQi8pthyqWr5D'
|
||||
course_invite_email: 'tem_ic2ZhPkpj8GBADFuyAp4bj'
|
||||
teacher_free_trial: 'tem_R7d9Hpoba9SceQNiYSXBak'
|
||||
teacher_free_trial_hoc: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc'
|
||||
teacher_request_demo: 'tem_cwG3HZjEyb6QE493hZuUra'
|
||||
password_reset: 'tem_wbQUMRtLY9xhec8BSCykLA'
|
||||
parent_subscribe_email: { id: 'tem_2APERafogvwKhmcnouigud' }
|
||||
share_progress_email: { id: 'tem_VHE3ihhGmVa3727qds9zY8' }
|
||||
welcome_email_user: { id: 'tem_z7Xvj3mtWYk6ec6aW7RwFk' }
|
||||
welcome_email_student: { id: 'tem_4WYPZNLzs5wawMF9qUJXUH' }
|
||||
verify_email: { id: 'tem_zJee6uRsRmzqzktzneCkCn' }
|
||||
ladder_update_email: { id: 'JzaZxf39A4cKMxpPZUfWy4' }
|
||||
patch_created: { id: 'tem_xhxuNosLALsizTNojBjNcL' }
|
||||
change_made_notify_watcher: { id: 'tem_7KVkfmv9SZETb25dtHbUtG' }
|
||||
recruiting_email: { id: 'tem_mdFMgtcczHKYu94Jmq68j8' }
|
||||
greed_tournament_rank: { id: 'tem_c4KYnk2TriEkkZx5NqqGLG' }
|
||||
generic_email: { id: 'tem_JhRnQ4pvTS4KdQjYoZdbei' }
|
||||
plain_text_email: { id: 'tem_85UvKDCCNPXsFckERTig6Y' }
|
||||
next_steps_email: { id: 'tem_RDHhTG5inXQi8pthyqWr5D' }
|
||||
course_invite_email: { id: 'tem_u6D2EFWYC5Ptk38bSykjsU', version: 'v3' }
|
||||
teacher_free_trial: { id: 'tem_R7d9Hpoba9SceQNiYSXBak' }
|
||||
teacher_free_trial_hoc: { id: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc' }
|
||||
teacher_request_demo: { id: 'tem_cwG3HZjEyb6QE493hZuUra' }
|
||||
password_reset: { id: 'tem_wbQUMRtLY9xhec8BSCykLA' }
|
||||
|
|
|
@ -75,24 +75,29 @@ describe 'TeacherClassView', ->
|
|||
# it "shows the classroom's join code"
|
||||
|
||||
describe 'the Students tab', ->
|
||||
beforeEach ->
|
||||
beforeEach (done) ->
|
||||
@view.state.set('activeTab', '#students-tab')
|
||||
_.defer(done)
|
||||
|
||||
# it 'shows all of the students'
|
||||
# it 'sorts correctly by Name'
|
||||
# it 'sorts correctly by Progress'
|
||||
|
||||
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)
|
||||
@view.$('.student-row .checkbox-flat').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)
|
||||
@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', ->
|
||||
# it 'shows the correct Course Overview progress'
|
||||
|
|
Loading…
Reference in a new issue