Merge branch 'master' into production

This commit is contained in:
Matt Lott 2015-12-12 13:16:38 -08:00
commit 03bc785201
12 changed files with 121 additions and 64 deletions

View file

@ -15,19 +15,31 @@ userPropsToSave =
module.exports = FacebookHandler = class FacebookHandler extends CocoClass
subscriptions:
'auth:logged-in-with-facebook': 'onFacebookLoggedIn'
loggedIn: false
onFacebookLoggedIn: (e) ->
# user is logged in also when the page first loads, so check to see
# if we really need to do the lookup
return if not me
doIt = false
@loggedIn = false
@authResponse = e.response.authResponse
for fbProp, userProp of userPropsToSave
unless me.get(userProp)
doIt = true
@loggedIn = true
break
FB.api('/me', @onReceiveMeInfo) if doIt
if @waitingForLogin and @loggedIn
@fetchMeForLogin()
loginThroughFacebook: ->
if @loggedIn
@fetchMeForLogin()
else
FB.login()
@waitingForLogin = true
fetchMeForLogin: ->
FB.api('/me', @onReceiveMeInfo)
onReceiveMeInfo: (r) =>
unless r.email

View file

@ -4,7 +4,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
no_ie: "O CodeCombat não funciona no Internet Explorer 8 ou anterior. Desculpa!" # Warning that only shows up in IE8 and older
no_mobile: "O CodeCombat não foi feito para dispositivos móveis e pode não funcionar!" # Warning that shows up on mobile devices
play: "Jogar" # The big play button that opens up the campaign view.
# play_campaign_version: "Play Campaign Version" # Shows up under big play button if you only play /courses
play_campaign_version: "Jogar Versão da Campanha" # Shows up under big play button if you only play /courses
old_browser: "Uh oh, o teu navegador é demasiado antigo para que o CodeCombat funcione. Desculpa!" # Warning that shows up on really old Firefox/Chrome/Safari
old_browser_suffix: "Podes tentar na mesma, mas provavelmente não vai funcionar."
ipad_browser: "Más notícias: o CodeCombat não funciona no navegador do iPad. Boas notícias: a nossa aplicação nativa para iPad está à espera da aprovação da Apple."
@ -78,7 +78,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
subscription_required: "Subscrição Necessária"
anonymous: "Jogador Anónimo"
level_difficulty: "Dificuldade: "
# play_classroom_version: "Play Classroom Version" # Choose a level in campaign version that you also can play in one of your courses
play_classroom_version: "Jogar Versão da Turma" # Choose a level in campaign version that you also can play in one of your courses
campaign_beginner: "Campanha para Iniciantes"
awaiting_levels_adventurer_prefix: "Lançamos novos níveis todas as semanas."
awaiting_levels_adventurer: "Regista-te como Aventureiro"
@ -118,9 +118,9 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
social_signup: "Ou podes registar-te através do FB ou do Google+:"
required: "Precisas de iniciar sessão antes de prosseguires."
login_switch: "Já tens uma conta?"
# school_name: "School Name and City"
# optional: "optional"
# school_name_placeholder: "Example High School, Springfield, IL"
school_name: "Nome e Cidade da Escola"
optional: "opcional"
school_name_placeholder: "Exemplo: Escola Secundária, Springfield, Illinois"
recover:
recover_account_title: "Recuperar Conta"
@ -674,8 +674,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
being_reviewed_1: "A tua aplicação para uma avaliação gratuita está a ser"
being_reviewed_2: "revista."
approved_1: "A tua aplicação para uma avaliação gratuita foi"
approved_2: "aprovada." # {change}
approved_4: "Inscreve os teus alunos na" # {change}
approved_2: "aprovada!"
approved_4: "Agora podes inscrever os teus alunos na"
approved_5: "página"
approved_6: "dos cursos."
denied_1: "A tua aplicação para uma avaliação gratuita foi"
@ -860,24 +860,24 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
playtime: "Tempo de jogo"
last_played: "Última vez jogado"
leagues_explanation: "Joga numa liga contra outros membros do clã nestas instâncias de arenas multijogador."
# track_concepts1: "Track concepts"
# track_concepts2a: "learned by each student"
# track_concepts2b: "learned by each member"
# track_concepts3a: "Track levels completed for each student"
# track_concepts3b: "Track levels completed for each member"
# track_concepts4a: "See your students'"
# track_concepts4b: "See your members'"
# track_concepts5: "solutions"
# track_concepts6a: "Sort students by name or progress"
# track_concepts6b: "Sort members by name or progress"
# track_concepts7: "Requires invitation"
# track_concepts8: "to join"
# private_require_sub: "Private clans require a subscription to create or join."
track_concepts1: "Acompanhe os conceitos"
track_concepts2a: "aprendidos por cada estudante"
track_concepts2b: "aprendidos por cada membro"
track_concepts3a: "Acompanhe os níveis completados por cada estudante"
track_concepts3b: "Acompanhe os níveis completados por cada membro"
track_concepts4a: "Veja, dos seus alunos, as"
track_concepts4b: "Veja, dos seus membros, as"
track_concepts5: "soluções"
track_concepts6a: "Ordene os alunos por nome ou progresso"
track_concepts6b: "Ordene os membros por nome ou progresso"
track_concepts7: "É necessário um convite"
track_concepts8: "para se juntar"
private_require_sub: "É necessária uma subscrição para criar ou entrar num clã privado."
courses:
course: "Curso"
courses: "cursos"
# create_new_class: "Create New Class"
create_new_class: "Criar Turma Nova"
not_enrolled: "Não estás inscrito neste curso."
visit_pref: "Por favor visita a página dos"
visit_suf: "para te inscreveres."
@ -1316,7 +1316,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
tutorial_skip: "Saltar Tutorial"
tutorial_not_sure: "Não tens a certeza do que se passa?"
tutorial_play_first: "Joga o Tutorial primeiro."
simple_ai: "IA Simples" # {change}
simple_ai: "CPU Simples"
warmup: "Aquecimento"
friends_playing: "Amigos a Jogar"
log_in_for_friends: "Inicia sessão para jogares com os teus amigos!"
@ -1338,8 +1338,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
rules: "Regras"
winners: "Vencedores"
league: "Liga"
red_ai: "IA Vermelha" # "Red AI Wins", at end of multiplayer match playback
blue_ai: "IA Azul" # {change}
red_ai: "CPU Vermelho" # "Red AI Wins", at end of multiplayer match playback
blue_ai: "CPU Azul"
wins: "Vence" # At end of multiplayer match playback
humans: "Vermelho" # Ladder page display team name
ogres: "Azul"
@ -1491,16 +1491,16 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
campaigns: "Campanhas"
poll: "Votações"
user_polls_record: "Histórico das Votações"
# course: "Course"
# courses: "Courses"
# course_instance: "Course Instance"
# course_instances: "Course Instances"
# classroom: "Classroom"
# classrooms: "Classrooms"
# clan: "Clan"
# clans: "Clans"
# members: "Members"
# users: "Users"
course: "Curso"
courses: "Cursos"
course_instance: "Instância do Curso"
course_instances: "Instâncias do Curso"
classroom: "Turma"
classrooms: "Turmas"
clan: "Clã"
clans: "Clãs"
members: "Membros"
users: "Utilizadores"
concepts:
advanced_strings: "'Strings' Avançadas"

View file

@ -4,6 +4,20 @@
#main-account-view
#account-links
width: 300px
#account-links .btn
width: 100%
width: 100%
padding: 35px
margin-bottom: 10%
font-size: 25px
background-image: linear-gradient(to bottom, rgba(181,169,125,0), rgba(181,169,125,255))
font-weight: 600
.logout-btn
font-weight: bold
.row-top-buffer
margin-top: 5%
.row-bot-buffer
margin-bottom: 7%

View file

@ -11,17 +11,23 @@ block content
a(href="/")
span.glyphicon.glyphicon-home
li.active(data-i18n="nav.account")
#account-links.panel.panel-default
.panel-heading(data-i18n="nav.account")
ul.list-group
li.list-group-item
a.btn.btn-lg.btn-primary(href="/user/#{me.getSlugOrID()}", data-i18n="nav.profile")
li.list-group-item
div.row.row-top-buffer
div.col-md-4
#account-links
a.btn.btn-lg.btn-primary(href="/user/#{me.getSlugOrID()}", data-i18n="nav.profile")
div.col-md-4
#account-links
a.btn.btn-lg.btn-primary(href="/account/settings", data-i18n="play.settings")
li.list-group-item
div.col-md-4
#account-links
a.btn.btn-lg.btn-primary(href="/account/payments", data-i18n="account.payments")
li.list-group-item
div.row.row-bot-buffer
div.col-md-4
#account-links
a.btn.btn-lg.btn-primary(href="/account/subscription", data-i18n="account.subscription")
li.list-group-item
div.col-md-4
#account-links
a.btn.btn-lg.btn-primary(href="/account/prepaid", data-i18n="account.prepaid_codes") Prepaid Codes
div.col-md-4
#account-links
a.btn.btn-lg.btn-primary.logout-btn(href="/account", data-i18n="login.log_out")

View file

@ -88,11 +88,9 @@
// btn.btn.btn-sm.github-login-button#github-login-button
// img(src="/images/pages/modal/auth/github_icon.png")
// | GitHub
.btn.btn-primary.btn-lg.btn-illustrated.network-login
#facebook-login-btn.btn.btn-primary.btn-lg.btn-illustrated.network-login
img.network-logo(src="/images/pages/community/logo_facebook.png", draggable="false")
span.sign-in-blurb(data-i18n="login.sign_in_with_facebook") Sign in with Facebook
.facebook-login-wrapper
.fb-login-button(data-show-faces="false", data-width="200", data-max-rows="1", data-scope="email")
.btn.btn-danger.btn-lg.btn-illustrated.network-login
img.network-logo(src="/images/pages/community/logo_g+.png", draggable="false")
span.sign-in-blurb(data-i18n="login.sign_in_with_gplus") Sign in with G+

View file

@ -139,23 +139,30 @@ block content
th(data-i18n="courses.concepts")
tbody
if campaign
- var lastLevelCompleted = true;
- var previousLevelCompleted = true;
- var lastLevelCompleted = view.getLastLevelCompleted();
- var passedLastCompletedLevel = false;
- var levelCount = 0;
each level, levelID in campaign.get('levels')
- var levelStatus = null;
if userLevelStateMap[me.id]
- levelStatus = userLevelStateMap[me.id][levelID]
tr
td
if lastLevelCompleted || view.teacherMode
if previousLevelCompleted || view.teacherMode || !passedLastCompletedLevel || levelStatus
- var i18n = level.type === 'course-ladder' ? 'play.compete' : 'home.play';
button.btn.btn-success.btn-play-level(data-level-slug=level.slug, data-i18n=i18n, data-level-id=levelID)
td
if userLevelStateMap[me.id]
div= userLevelStateMap[me.id][levelID]
- lastLevelCompleted = userLevelStateMap[me.id][levelID] === 'complete'
- previousLevelCompleted = userLevelStateMap[me.id][levelID] === 'complete'
else
- lastLevelCompleted = false
- previousLevelCompleted = false
td= ++levelCount + '. ' + level.name.replace('Course: ', '')
td
if levelConceptMap[levelID]
each concept in course.get('concepts')
if levelConceptMap[levelID][concept]
span.spr.concept(data-i18n="concepts." + concept)
if levelID === lastLevelCompleted
- passedLastCompletedLevel = true

View file

@ -66,7 +66,7 @@ block content
span.spr :
span.spr(data-i18n="courses.course")
span 1
span.spr= (me.get('aceConfig') || {}).language === 'python' ? 'Python' : 'JavaScript'
span.spr= (me.get('aceConfig') || {}).language === 'javascript' ? 'JavaScript' : 'Python'
small
a#change-language-link(data-i18n="courses.change_language")
+course-instance-body(view.hocCourseInstance)
@ -86,7 +86,7 @@ block content
div(class=classroomClass)
h3
span.spr= classroom.get('name')
span.spr (#{(classroom.get('aceConfig') || {}).language === 'python' ? 'Python' : 'JavaScript'})
span.spr (#{(classroom.get('aceConfig') || {}).language === 'javascript' ? 'JavaScript' : 'Python'})
a(href="/courses/"+classroom.id, data-i18n="courses.view_class")
- var courseInstances = view.courseInstances.where({classroomID: classroom.id});

View file

@ -3,4 +3,7 @@ template = require 'templates/account/main-account-view'
module.exports = class MainAccountView extends RootView
id: 'main-account-view'
template: template
template: template
events:
'click .logout-btn': 'logoutAccount'

View file

@ -19,6 +19,7 @@ module.exports = class AuthModal extends ModalView
'keyup #name': 'onNameChange'
'click #gplus-login-button': 'onClickGPlusLogin'
'click #close-modal': 'hide'
'click #facebook-login-btn': 'onClickFacebookLoginButton'
subscriptions:
'errors:server-error': 'onServerError'
@ -158,6 +159,9 @@ module.exports = class AuthModal extends ModalView
@$el.find('.modal-body:visible').empty().append(el)
@$el.find('.modal-footer').remove()
onClickFacebookLoginButton: ->
application.facebookHandler.loginThroughFacebook()
onHidden: ->
super()
@playSound 'game-menu-close'

View file

@ -238,3 +238,10 @@ module.exports = class CourseDetailsView extends RootView
else
storage.save 'no-school', true
@$el.find('#school-form').slideUp('slow')
getLastLevelCompleted: ->
lastLevelCompleted = null
for levelID in _.keys(@campaign.get('levels'))
if @userLevelStateMap?[me.id]?[levelID] is 'complete'
lastLevelCompleted = levelID
return lastLevelCompleted

View file

@ -348,7 +348,11 @@ module.exports = class Handler
return @sendForbiddenError(res) if @modelClass.schema.uses_coco_versions and not req.user.isAdmin() # Campaign editor just saves over things.
return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
return @sendForbiddenError(res) unless @hasAccess(req)
@getDocumentForIdOrSlug req.body._id or id, (err, document) =>
idOrSlug = req.body._id or id
if not idOrSlug or idOrSlug is 'undefined'
console.error "Bad PUT trying to fetching the slug: #{idOrSlug} for #{@modelClass.collection?.name} from #{req.headers['x-current-path']}?"
return @sendBadInputError(res, 'No _id field provided.')
@getDocumentForIdOrSlug idOrSlug, (err, document) =>
return @sendBadInputError(res, 'Bad id.') if err and err.name is 'CastError'
return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless document?
@ -502,7 +506,7 @@ module.exports = class Handler
query = @modelClass.findById(idOrSlug)
else
if not idOrSlug or idOrSlug is 'undefined'
console.error "What? Why are we fetching the slug: #{idOrSlug}?"
console.error "Bad request trying to fetching the slug: #{idOrSlug} for #{@modelClass.collection?.name}"
console.trace()
return done null, null
query = @modelClass.findOne {slug: idOrSlug}

View file

@ -51,6 +51,7 @@ mockMe =
window.FB ?= {
api: ->
login: ->
}
describe 'lib/FacebookHandler.coffee', ->
@ -61,7 +62,8 @@ describe 'lib/FacebookHandler.coffee', ->
spyOn FB, 'api'
new FacebookHandler()
facebookHandler = new FacebookHandler()
facebookHandler.loginThroughFacebook()
Backbone.Mediator.publish 'auth:logged-in-with-facebook', mockAuthEvent
expect(FB.api).toHaveBeenCalled()