Merge branch 'master' into production
This commit is contained in:
commit
dd66018ece
10 changed files with 252 additions and 28 deletions
app
lib/surface
locale
schemas/models
views
ladder
play
common
level/tome
modal
scripts
server/queues/scoring
|
@ -42,7 +42,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
||||||
buildAutomatically: true
|
buildAutomatically: true
|
||||||
buildAsync: true
|
buildAsync: true
|
||||||
resolutionFactor: SPRITE_RESOLUTION_FACTOR
|
resolutionFactor: SPRITE_RESOLUTION_FACTOR
|
||||||
defaultActions: ['idle', 'die', 'move', 'move', 'attack']
|
defaultActions: ['idle', 'die', 'move', 'attack']
|
||||||
numThingsLoading: 0
|
numThingsLoading: 0
|
||||||
lanks: null
|
lanks: null
|
||||||
spriteSheet: null
|
spriteSheet: null
|
||||||
|
@ -147,9 +147,6 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
||||||
#- Adding, removing children for WebGL layers.
|
#- Adding, removing children for WebGL layers.
|
||||||
|
|
||||||
addLank: (lank) ->
|
addLank: (lank) ->
|
||||||
# TODO: Move this into the production DB rather than setting it dynamically.
|
|
||||||
if lank.thangType?.get('name') is 'Highlight'
|
|
||||||
lank.thangType.set('spriteType', 'segmented')
|
|
||||||
lank.options.resolutionFactor = @resolutionFactor
|
lank.options.resolutionFactor = @resolutionFactor
|
||||||
|
|
||||||
lank.layer = @
|
lank.layer = @
|
||||||
|
|
|
@ -99,13 +99,13 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
authenticate_gplus: "Autenticar com G+"
|
authenticate_gplus: "Autenticar com G+"
|
||||||
load_profile: "Carregar Perfil do G+"
|
load_profile: "Carregar Perfil do G+"
|
||||||
finishing: "Terminando"
|
finishing: "Terminando"
|
||||||
sign_in_with_facebook: "Conectar com Facebook"
|
sign_in_with_facebook: "Conectar com o Facebook"
|
||||||
sign_in_with_gplus: "Conectar com G+"
|
sign_in_with_gplus: "Conectar com o G+"
|
||||||
signup_switch: "Deseja Criar uma Conta?"
|
signup_switch: "Deseja Criar uma Conta?"
|
||||||
|
|
||||||
signup:
|
signup:
|
||||||
email_announcements: "Receber notícias por email."
|
email_announcements: "Receber notícias por email."
|
||||||
creating: "Criando a nova conta..."
|
creating: "Criando uma nova conta..."
|
||||||
sign_up: "Criar conta"
|
sign_up: "Criar conta"
|
||||||
log_in: "Entre com a senha"
|
log_in: "Entre com a senha"
|
||||||
social_signup: "Ou, você pode fazer login pelo Facebook ou G+:"
|
social_signup: "Ou, você pode fazer login pelo Facebook ou G+:"
|
||||||
|
@ -137,7 +137,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
publish: "Publicar"
|
publish: "Publicar"
|
||||||
create: "Criar"
|
create: "Criar"
|
||||||
manual: "Manual"
|
manual: "Manual"
|
||||||
fork: "Fork"
|
fork: "Fork" # When used as a verb, like "To fork a repository"
|
||||||
play: "Jogar" # When used as an action verb, like "Play next level"
|
play: "Jogar" # When used as an action verb, like "Play next level"
|
||||||
retry: "Tente novamente"
|
retry: "Tente novamente"
|
||||||
actions: "Ações"
|
actions: "Ações"
|
||||||
|
@ -239,7 +239,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
victory: "Vitória"
|
victory: "Vitória"
|
||||||
victory_title_prefix: " Vitória "
|
victory_title_prefix: " Vitória "
|
||||||
victory_title_suffix: " Completado!"
|
victory_title_suffix: " Completado!"
|
||||||
victory_sign_up: "Assine para atualizações"
|
victory_sign_up: "Assine para receber atualizações"
|
||||||
victory_sign_up_poke: "Quer receber as últimas novidades por email? Crie uma conta grátis e nós o manteremos informado!"
|
victory_sign_up_poke: "Quer receber as últimas novidades por email? Crie uma conta grátis e nós o manteremos informado!"
|
||||||
victory_rate_the_level: "Avalie o estágio: " # Only in old-style levels.
|
victory_rate_the_level: "Avalie o estágio: " # Only in old-style levels.
|
||||||
victory_return_to_ladder: "Retornar para a progressão"
|
victory_return_to_ladder: "Retornar para a progressão"
|
||||||
|
@ -251,7 +251,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
victory_hour_of_code_done: "Terminou?"
|
victory_hour_of_code_done: "Terminou?"
|
||||||
victory_hour_of_code_done_yes: "Sim, eu terminei minha Hora da Programação!"
|
victory_hour_of_code_done_yes: "Sim, eu terminei minha Hora da Programação!"
|
||||||
victory_experience_gained: "XP ganho"
|
victory_experience_gained: "XP ganho"
|
||||||
victory_gems_gained: "Gems ganhas"
|
victory_gems_gained: "Gemas ganhas"
|
||||||
victory_new_item: "Novo item"
|
victory_new_item: "Novo item"
|
||||||
victory_viking_code_school: "Pelas barbas do profeta, esse foi um nível difícil! Se você ainda não é um desenvolvedor de software, você deveria ser. Você acaba de ser priorizado para aceitação na Viking Code School, onde você pode aprender mais e se tornar um desenvolvedor web profissional em 14 semanas."
|
victory_viking_code_school: "Pelas barbas do profeta, esse foi um nível difícil! Se você ainda não é um desenvolvedor de software, você deveria ser. Você acaba de ser priorizado para aceitação na Viking Code School, onde você pode aprender mais e se tornar um desenvolvedor web profissional em 14 semanas."
|
||||||
victory_become_a_viking: "Torne-se um viking"
|
victory_become_a_viking: "Torne-se um viking"
|
||||||
|
@ -288,7 +288,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
infinite_loop_title: "Loop Infinito Detectado"
|
infinite_loop_title: "Loop Infinito Detectado"
|
||||||
infinite_loop_description: "O código inicial para construir o mundo nunca parou de rodar. Talvez seja muito lento ou tenha um loop infinito. Ou talvez tenha um bug. Você pode tentar rodar este código novamente ou resetá-lo para o estado inicial. Se isto não consertá-lo, avise-nos por favor."
|
infinite_loop_description: "O código inicial para construir o mundo nunca parou de rodar. Talvez seja muito lento ou tenha um loop infinito. Ou talvez tenha um bug. Você pode tentar rodar este código novamente ou resetá-lo para o estado inicial. Se isto não consertá-lo, avise-nos por favor."
|
||||||
check_dev_console: "Você também pode abrir o terminal do desenvolvedor para ver o que pode estar dando errado."
|
check_dev_console: "Você também pode abrir o terminal do desenvolvedor para ver o que pode estar dando errado."
|
||||||
check_dev_console_link: "(instruções)"
|
check_dev_console_link: "(Instruções)"
|
||||||
infinite_loop_try_again: "Tentar novamente"
|
infinite_loop_try_again: "Tentar novamente"
|
||||||
infinite_loop_reset_level: "Resetar nível"
|
infinite_loop_reset_level: "Resetar nível"
|
||||||
infinite_loop_comment_out: "Comentar Meu Código"
|
infinite_loop_comment_out: "Comentar Meu Código"
|
||||||
|
@ -296,7 +296,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
tip_scrub_shortcut: "Ctrl+[ e Ctrl+] rebobina e avança." # {change}
|
tip_scrub_shortcut: "Ctrl+[ e Ctrl+] rebobina e avança." # {change}
|
||||||
tip_guide_exists: "Clique no guia no topo da página para informações úteis."
|
tip_guide_exists: "Clique no guia no topo da página para informações úteis."
|
||||||
tip_open_source: "CodeCombat é 100% código aberto!"
|
tip_open_source: "CodeCombat é 100% código aberto!"
|
||||||
tip_tell_friends: "Está gostando de CodeCombate? Dibulgue para os seus amigos!"
|
tip_tell_friends: "Está gostando de CodeCombate? Divulgue para os seus amigos!"
|
||||||
tip_beta_launch: "CodeCombat lançou sua versão beta em outubro de 2013."
|
tip_beta_launch: "CodeCombat lançou sua versão beta em outubro de 2013."
|
||||||
tip_think_solution: "Pense na solução, não no problema."
|
tip_think_solution: "Pense na solução, não no problema."
|
||||||
tip_theory_practice: "Na teoria, não existe diferença entre teoria e prática. Mas, na prática, há. - Yogi Berra"
|
tip_theory_practice: "Na teoria, não existe diferença entre teoria e prática. Mas, na prática, há. - Yogi Berra"
|
||||||
|
@ -582,15 +582,15 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
||||||
press_paragraph_1_link: "Midia Kit"
|
press_paragraph_1_link: "Midia Kit"
|
||||||
press_paragraph_1_suffix: ". Todas as logomarcas e imagens podem ser usadas sem nos contactar previamente."
|
press_paragraph_1_suffix: ". Todas as logomarcas e imagens podem ser usadas sem nos contactar previamente."
|
||||||
team: "Time"
|
team: "Time"
|
||||||
george_title: "CEO" # {change}
|
george_title: "Cofundador"
|
||||||
george_blurb: "Administrador"
|
george_blurb: "Administrador"
|
||||||
scott_title: "Programador" # {change}
|
scott_title: "Cofundador"
|
||||||
scott_blurb: "O Sensato"
|
scott_blurb: "O Sensato"
|
||||||
nick_title: "Programador" # {change}
|
nick_title: "Cofundador"
|
||||||
nick_blurb: "Guru Motivacional"
|
nick_blurb: "Guru Motivacional"
|
||||||
michael_title: "Programador"
|
michael_title: "Programador"
|
||||||
michael_blurb: "Administrador de Sistemas"
|
michael_blurb: "Administrador de Sistemas"
|
||||||
matt_title: "Programador" # {change}
|
matt_title: "Cofundador"
|
||||||
matt_blurb: "O Ciclista"
|
matt_blurb: "O Ciclista"
|
||||||
cat_title: "Chefe Artesão"
|
cat_title: "Chefe Artesão"
|
||||||
cat_blurb: "Corta-vento"
|
cat_blurb: "Corta-vento"
|
||||||
|
|
|
@ -29,8 +29,8 @@ defaultTasks = [
|
||||||
'Release to adventurers via MailChimp.'
|
'Release to adventurers via MailChimp.'
|
||||||
|
|
||||||
'Write the description.'
|
'Write the description.'
|
||||||
'Translate the sample code comments.'
|
'Add i18n field for the sample code comments.'
|
||||||
'Add Io/Clojure/Lua/CoffeeScript.'
|
'Add Clojure/Lua/CoffeeScript.'
|
||||||
'Write the guide.'
|
'Write the guide.'
|
||||||
'Write a loading tip, if needed.'
|
'Write a loading tip, if needed.'
|
||||||
'Click the Populate i18n button.'
|
'Click the Populate i18n button.'
|
||||||
|
@ -40,7 +40,6 @@ defaultTasks = [
|
||||||
'Release to everyone via MailChimp.'
|
'Release to everyone via MailChimp.'
|
||||||
|
|
||||||
'Check completion/engagement/problem analytics.'
|
'Check completion/engagement/problem analytics.'
|
||||||
'Do any custom scripting, if needed.'
|
|
||||||
'Do thorough set decoration.'
|
'Do thorough set decoration.'
|
||||||
'Add a walkthrough video.'
|
'Add a walkthrough video.'
|
||||||
]
|
]
|
||||||
|
|
|
@ -101,7 +101,7 @@ module.exports = class LadderPlayModal extends ModalView
|
||||||
{id: 'coffeescript', name: 'CoffeeScript (Experimental)'}
|
{id: 'coffeescript', name: 'CoffeeScript (Experimental)'}
|
||||||
{id: 'clojure', name: 'Clojure (Experimental)'}
|
{id: 'clojure', name: 'Clojure (Experimental)'}
|
||||||
{id: 'lua', name: 'Lua'}
|
{id: 'lua', name: 'Lua'}
|
||||||
{id: 'io', name: 'Io (Experimental)'}
|
#{id: 'io', name: 'Io (Experimental)'}
|
||||||
]
|
]
|
||||||
ctx.league = @options.league
|
ctx.league = @options.league
|
||||||
teamsList = teamDataFromLevel @level
|
teamsList = teamDataFromLevel @level
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
CocoView = require 'views/core/CocoView'
|
CocoView = require 'views/core/CocoView'
|
||||||
template = require 'templates/play/common/ladder_submission'
|
template = require 'templates/play/common/ladder_submission'
|
||||||
{createAetherOptions} = require 'lib/aether_utils'
|
{createAetherOptions} = require 'lib/aether_utils'
|
||||||
|
LevelSession = require 'models/LevelSession'
|
||||||
|
|
||||||
module.exports = class LadderSubmissionView extends CocoView
|
module.exports = class LadderSubmissionView extends CocoView
|
||||||
className: 'ladder-submission-view'
|
className: 'ladder-submission-view'
|
||||||
|
@ -78,14 +79,20 @@ module.exports = class LadderSubmissionView extends CocoView
|
||||||
# Also submit the mirrorSession after the main session submits successfully.
|
# Also submit the mirrorSession after the main session submits successfully.
|
||||||
mirrorAjaxData = _.clone ajaxData
|
mirrorAjaxData = _.clone ajaxData
|
||||||
mirrorAjaxData.session = @mirrorSession.id
|
mirrorAjaxData.session = @mirrorSession.id
|
||||||
|
mirrorCode = @mirrorSession.get('code')
|
||||||
if @session.get('team') is 'humans'
|
if @session.get('team') is 'humans'
|
||||||
mirrorAjaxData.transpiledCode = 'hero-placeholder-1': transpiledCode['hero-placeholder']
|
mirrorAjaxData.transpiledCode = 'hero-placeholder-1': transpiledCode['hero-placeholder']
|
||||||
|
mirrorCode['hero-placeholder-1'] = @session.get('code')['hero-placeholder']
|
||||||
else
|
else
|
||||||
mirrorAjaxData.transpiledCode = 'hero-placeholder': transpiledCode['hero-placeholder-1']
|
mirrorAjaxData.transpiledCode = 'hero-placeholder': transpiledCode['hero-placeholder-1']
|
||||||
|
mirrorCode['hero-placeholder'] = @session.get('code')['hero-placeholder-1']
|
||||||
mirrorAjaxOptions = _.clone ajaxOptions
|
mirrorAjaxOptions = _.clone ajaxOptions
|
||||||
mirrorAjaxOptions.data = mirrorAjaxData
|
mirrorAjaxOptions.data = mirrorAjaxData
|
||||||
ajaxOptions.success = ->
|
ajaxOptions.success = =>
|
||||||
$.ajax '/queue/scoring', mirrorAjaxOptions
|
patch = code: mirrorCode, codeLanguage: @session.get('codeLanguage'), submittedCodeLanguage: @session.get('submittedCodeLanguage')
|
||||||
|
tempSession = new LevelSession _id: @mirrorSession.id
|
||||||
|
tempSession.save patch, patch: true, type: 'PUT', success: ->
|
||||||
|
$.ajax '/queue/scoring', mirrorAjaxOptions
|
||||||
|
|
||||||
$.ajax '/queue/scoring', ajaxOptions
|
$.ajax '/queue/scoring', ajaxOptions
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,9 @@ module.exports = class CastButtonView extends CocoView
|
||||||
@casting = false
|
@casting = false
|
||||||
if @hasCastOnce # Don't play this sound the first time
|
if @hasCastOnce # Don't play this sound the first time
|
||||||
@playSound 'cast-end', 0.5
|
@playSound 'cast-end', 0.5
|
||||||
_.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
|
myHeroID = if me.team is 'ogres' then 'Hero Placeholder 1' else 'Hero Placeholder'
|
||||||
|
if @ladderSubmissionView and not e.world.thangMap[myHeroID]?.errorsOut
|
||||||
|
_.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
|
||||||
@hasCastOnce = true
|
@hasCastOnce = true
|
||||||
@updateCastButton()
|
@updateCastButton()
|
||||||
@world = e.world
|
@world = e.world
|
||||||
|
|
|
@ -36,7 +36,7 @@ module.exports = class Spell
|
||||||
else
|
else
|
||||||
@setLanguage 'javascript'
|
@setLanguage 'javascript'
|
||||||
@useTranspiledCode = @shouldUseTranspiledCode()
|
@useTranspiledCode = @shouldUseTranspiledCode()
|
||||||
console.log 'Spell', @spellKey, 'is using transpiled code (should only happen if it\'s an enemy/spectate writable method).' if @useTranspiledCode
|
#console.log 'Spell', @spellKey, 'is using transpiled code (should only happen if it\'s an enemy/spectate writable method).' if @useTranspiledCode
|
||||||
|
|
||||||
@source = @originalSource
|
@source = @originalSource
|
||||||
@parameters = p.parameters
|
@parameters = p.parameters
|
||||||
|
|
|
@ -113,7 +113,7 @@ module.exports = class PlayHeroesModal extends ModalView
|
||||||
{id: 'coffeescript', name: "CoffeeScript (#{$.i18n.t('choose_hero.experimental')})"}
|
{id: 'coffeescript', name: "CoffeeScript (#{$.i18n.t('choose_hero.experimental')})"}
|
||||||
{id: 'clojure', name: "Clojure (#{$.i18n.t('choose_hero.experimental')})"}
|
{id: 'clojure', name: "Clojure (#{$.i18n.t('choose_hero.experimental')})"}
|
||||||
{id: 'lua', name: 'Lua'}
|
{id: 'lua', name: 'Lua'}
|
||||||
{id: 'io', name: "Io (#{$.i18n.t('choose_hero.experimental')})"}
|
#{id: 'io', name: "Io (#{$.i18n.t('choose_hero.experimental')})"}
|
||||||
]
|
]
|
||||||
|
|
||||||
onHeroChanged: (e) ->
|
onHeroChanged: (e) ->
|
||||||
|
|
221
scripts/helpScoutToCloseIO.js
Normal file
221
scripts/helpScoutToCloseIO.js
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
// Copy sales leads from HelpScout to Close.io based on HelpScout tags
|
||||||
|
|
||||||
|
// TODO: handle leads with multiple email addresses
|
||||||
|
// TODO: some feedback email threads get broken up in Close.io
|
||||||
|
|
||||||
|
var CloseIo = function (apiKey, mailboxEmail) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
this.mailboxEmail = mailboxEmail;
|
||||||
|
}
|
||||||
|
CloseIo.prototype.createLead = function (conversation, done) {
|
||||||
|
console.log('Close.Io - Creating lead for', conversation.customer.email);
|
||||||
|
var data = {
|
||||||
|
contacts: [{
|
||||||
|
emails: [{
|
||||||
|
email: conversation.customer.email,
|
||||||
|
type: 'office'
|
||||||
|
}],
|
||||||
|
name: conversation.customer.firstName + ' ' + conversation.customer.lastName
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
var options = {
|
||||||
|
uri: 'https://' + this.apiKey+ ':X@app.close.io/api/v1/lead/',
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
};
|
||||||
|
request.post(options, function (error, response, body) {
|
||||||
|
if (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
return done(null, JSON.parse(body));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CloseIo.prototype.getActivities = function (leadID, done) {
|
||||||
|
// console.log('Close.Io - Retrieving activities for lead', leadID);
|
||||||
|
request.get('https://' + this.apiKey + ':X@app.close.io/api/v1/activity/email/?lead_id=' + leadID, function(error, response, body) {
|
||||||
|
if (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
return done(null, JSON.parse(body));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CloseIo.prototype.getLead = function (conversation, done) {
|
||||||
|
// console.log('Close.Io - Retrieving contact', conversation.customer.email);
|
||||||
|
var uri = 'https://' + this.apiKey + ':X@app.close.io/api/v1/lead/?query=email_address:' + conversation.customer.email;
|
||||||
|
request.get(uri, (function(error, response, body) {
|
||||||
|
if (error) return done(error);
|
||||||
|
var leads = JSON.parse(body);
|
||||||
|
if (leads.data.length === 1) {
|
||||||
|
return done(null, leads.data[0]);
|
||||||
|
}
|
||||||
|
else if (leads.data.length > 1) {
|
||||||
|
return done('ERROR: too many leads returned for ' + conversation.customer.email + ' ' + leads.data.length);
|
||||||
|
}
|
||||||
|
this.createLead(conversation, (function(error, lead) {
|
||||||
|
if (error) return done(error);
|
||||||
|
return done(null, lead);
|
||||||
|
}).bind(this));
|
||||||
|
}).bind(this));
|
||||||
|
}
|
||||||
|
CloseIo.prototype.updateActivity = function (activities, lead, conversation, conversationThread, done) {
|
||||||
|
// console.log('Close.Io - Updating email thread', conversation.subject);
|
||||||
|
var data = {
|
||||||
|
body_html: conversationThread.body,
|
||||||
|
contact_id: lead.contacts[0].id,
|
||||||
|
date_created: conversationThread.createdAt,
|
||||||
|
lead_id: lead.id,
|
||||||
|
sender: conversationThread.createdBy.email,
|
||||||
|
_type: 'Email'
|
||||||
|
}
|
||||||
|
if (conversation.subject) {
|
||||||
|
data.subject = conversation.subject;
|
||||||
|
if (data.subject.substring(0, 4) === 'Re: ') {
|
||||||
|
data.subject = data.subject.substring(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conversationThread.createdBy.email === this.mailboxEmail) {
|
||||||
|
data.status = 'sent';
|
||||||
|
data.to = [conversationThread.customer.email];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.status = 'inbox';
|
||||||
|
data.to = [this.mailboxEmail];
|
||||||
|
}
|
||||||
|
for (var i = 0; i < activities.data.length; i++) {
|
||||||
|
if (activities.data[i].body_html === data.body_html
|
||||||
|
&& new Date(activities.data[i].date_created).getTime() == new Date(data.date_created).getTime()) {
|
||||||
|
// console.log('Close.Io - Found existing email', data.subject, data.date_created);
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var options = {
|
||||||
|
uri: 'https://' + this.apiKey + ':X@app.close.io/api/v1/activity/email/',
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
};
|
||||||
|
request.post(options, function (error, response, body) {
|
||||||
|
if (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CloseIo.prototype.updateLead = function (conversation, done) {
|
||||||
|
console.log('Close.Io - Updating lead', conversation.customer.email);
|
||||||
|
this.getLead(conversation, (function(error, lead) {
|
||||||
|
if (error) return done(error);
|
||||||
|
this.updateLeadEmails(lead, conversation, (function(error) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}).bind(this));
|
||||||
|
}).bind(this));
|
||||||
|
}
|
||||||
|
CloseIo.prototype.updateLeadEmails = function (lead, conversation, done) {
|
||||||
|
console.log('Close.Io - Updating lead emails', lead.display_name, conversation.subject);
|
||||||
|
if (conversation.type !== 'email') return done();
|
||||||
|
this.getActivities(lead.id, (function(error, activities) {
|
||||||
|
if (error) return done(error);
|
||||||
|
for (var i = 0; i < conversation.threads.length; i++) {
|
||||||
|
if (conversation.threads[i].type !== 'message') continue;
|
||||||
|
if (conversation.threads[i].state !== 'published') continue;
|
||||||
|
if (!conversation.threads[i].body || conversation.threads[i].body.length === 0) continue;
|
||||||
|
this.updateActivity(activities, lead, conversation, conversation.threads[i], done);
|
||||||
|
}
|
||||||
|
}).bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
var HelpScout = function (apiKey, mailboxEmails, searchTag) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
this.mailboxEmails = mailboxEmails;
|
||||||
|
this.searchTag = searchTag;
|
||||||
|
}
|
||||||
|
HelpScout.prototype.getConversation = function (conversationId, done) {
|
||||||
|
// console.log('HelpScout - Retrieving conversation', conversationId);
|
||||||
|
request.get('https://' + this.apiKey + ':X@api.helpscout.net/v1/conversations/' + conversationId + '.json', function (error, response, body) {
|
||||||
|
if (error) return done(error);
|
||||||
|
var conversation = JSON.parse(body);
|
||||||
|
return done(null, conversation.item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
HelpScout.prototype.getConversations = function (mailboxId, done) {
|
||||||
|
// console.log('HelpScout - Retrieving conversations for mailbox', mailboxId);
|
||||||
|
var results = [];
|
||||||
|
var fetchPage = (function (page) {
|
||||||
|
// console.error("HelpScout - Fetching conversations page", page);
|
||||||
|
var uri = 'https://' + this.apiKey + ':X@api.helpscout.net/v1/mailboxes/' + mailboxId + '/conversations.json'
|
||||||
|
uri += '?page=' + page + '&tag=' + this.searchTag;
|
||||||
|
request.get(uri, function (error, response, body) {
|
||||||
|
if (error) return done(error);
|
||||||
|
var conversations = JSON.parse(body);
|
||||||
|
results = results.concat(conversations.items);
|
||||||
|
if (conversations.page < conversations.pages) {
|
||||||
|
return fetchPage(page + 1);
|
||||||
|
}
|
||||||
|
return done(null, results);
|
||||||
|
});
|
||||||
|
}).bind(this);
|
||||||
|
fetchPage(1);
|
||||||
|
}
|
||||||
|
HelpScout.prototype.getMailboxes = function (done) {
|
||||||
|
// console.log('HelpScout - Retrieving mailboxes');
|
||||||
|
var results = [];
|
||||||
|
request.get('https://' + this.apiKey + ':X@api.helpscout.net/v1/mailboxes.json', (function (error, response, body) {
|
||||||
|
if (error) return done(error);
|
||||||
|
var mailboxes = JSON.parse(body);
|
||||||
|
for (var i = 0 ; i < mailboxes.items.length; i++) {
|
||||||
|
if (this.mailboxEmails.indexOf(mailboxes.items[i].email) >= 0) {
|
||||||
|
results.push(mailboxes.items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return done(null, results);
|
||||||
|
}).bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main program
|
||||||
|
|
||||||
|
if (process.argv.length !== 4) {
|
||||||
|
log("Usage: node <script> <HelpScout API key> <Close.io API key>");
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = require('request');
|
||||||
|
var helpScout = new HelpScout(process.argv[2], ['support@codecombat.com', 'team@codecombat.com'], 'make the sale');
|
||||||
|
var closeIo = new CloseIo(process.argv[3], 'matt@codecombat.com');
|
||||||
|
|
||||||
|
helpScout.getMailboxes(function (error, mailboxes) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < mailboxes.length; i++) {
|
||||||
|
var mailbox = mailboxes[i];
|
||||||
|
helpScout.getConversations(mailbox.id, function(error, conversations) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(mailbox.email, 'mailbox has', conversations.length, 'conversations');
|
||||||
|
for (var i = 0; i < conversations.length; i++) {
|
||||||
|
if (conversations[i].type !== 'email') continue;
|
||||||
|
|
||||||
|
if (i > 8) {
|
||||||
|
console.log('TODO: process all the conversations');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
helpScout.getConversation(conversations[i].id, function(error, conversation) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeIo.updateLead(conversation, function(error, lead) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -17,7 +17,7 @@ sessionSelectionString = 'team totalScore transpiledCode submittedCodeLanguage t
|
||||||
sendSessionsResponse = (res) ->
|
sendSessionsResponse = (res) ->
|
||||||
(err, sessions) ->
|
(err, sessions) ->
|
||||||
if err then return errors.serverError res, "Couldn't get two games to simulate: #{err}"
|
if err then return errors.serverError res, "Couldn't get two games to simulate: #{err}"
|
||||||
unless sessions.length is 2
|
unless _.filter(sessions).length is 2
|
||||||
console.log 'No games to score.', sessions.length
|
console.log 'No games to score.', sessions.length
|
||||||
res.send 204, 'No games to score.'
|
res.send 204, 'No games to score.'
|
||||||
return res.end()
|
return res.end()
|
||||||
|
@ -110,5 +110,3 @@ findEarliestSubmission = (queryParams, callback) ->
|
||||||
return callback err if err
|
return callback err if err
|
||||||
result = earliestSubmissionCache[cacheKey] = earliest?.submitDate
|
result = earliestSubmissionCache[cacheKey] = earliest?.submitDate
|
||||||
callback null, result
|
callback null, result
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in a new issue