mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Merge branch 'master' into achievements
This commit is contained in:
commit
0288786098
23 changed files with 269 additions and 51 deletions
|
@ -25,8 +25,10 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
# Direct links
|
||||
'test': go('TestView')
|
||||
'test/*subpath': go('TestView')
|
||||
|
||||
'demo': go('DemoView')
|
||||
'demo/*subpath': go('DemoView')
|
||||
|
||||
'play/ladder/:levelID': go('play/ladder/ladder_view')
|
||||
'play/ladder': go('play/ladder_home')
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ module.exports.formToObject = (el) ->
|
|||
|
||||
obj
|
||||
|
||||
module.exports.applyErrorsToForm = (el, errors) ->
|
||||
module.exports.applyErrorsToForm = (el, errors, warning=false) ->
|
||||
errors = [errors] if not $.isArray(errors)
|
||||
missingErrors = []
|
||||
for error in errors
|
||||
if error.dataPath
|
||||
prop = error.dataPath[1..]
|
||||
console.log prop
|
||||
message = error.message
|
||||
|
||||
else
|
||||
|
@ -23,16 +23,28 @@ module.exports.applyErrorsToForm = (el, errors) ->
|
|||
message = error.message if error.formatted
|
||||
prop = error.property
|
||||
|
||||
input = $("[name='#{prop}']", el)
|
||||
if not input.length
|
||||
missingErrors.push(error)
|
||||
continue
|
||||
formGroup = input.closest('.form-group')
|
||||
formGroup.addClass 'has-error'
|
||||
formGroup.append($("<span class='help-block error-help-block'>#{message}</span>"))
|
||||
return missingErrors
|
||||
setErrorToProperty el, prop, message, warning
|
||||
|
||||
module.exports.setErrorToField = setErrorToField = (el, message, warning=false) ->
|
||||
formGroup = el.closest('.form-group')
|
||||
unless formGroup.length
|
||||
return console.error "#{el} did not contain a form group"
|
||||
|
||||
kind = if warning then 'warning' else 'error'
|
||||
formGroup.addClass "has-#{kind}"
|
||||
formGroup.append $("<span class='help-block #{kind}-help-block'>#{message}</span>")
|
||||
|
||||
module.exports.setErrorToProperty = setErrorToProperty = (el, property, message, warning=false) ->
|
||||
input = $("[name='#{property}']", el)
|
||||
unless input.length
|
||||
return console.error "#{property} not found in #{el}"
|
||||
|
||||
setErrorToField input, message, warning
|
||||
|
||||
module.exports.clearFormAlerts = (el) ->
|
||||
$('.has-error', el).removeClass('has-error')
|
||||
$('.has-warning', el).removeClass('has-warning')
|
||||
$('.alert.alert-danger', el).remove()
|
||||
$('.alert.alert-warning', el).remove()
|
||||
el.find('.help-block.error-help-block').remove()
|
||||
el.find('.help-block.warning-help-block').remove()
|
||||
|
|
|
@ -242,7 +242,17 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
args = JSON.parse(event[4...])
|
||||
pos = @options.camera.worldToSurface {x: args[0], y: args[1]}
|
||||
circle = new createjs.Shape()
|
||||
circle.graphics.beginFill(args[3]).drawCircle(0, 0, args[2]*Camera.PPM)
|
||||
radius = args[2] * Camera.PPM
|
||||
if args.length is 4
|
||||
circle.graphics.beginFill(args[3]).drawCircle(0, 0, radius)
|
||||
else
|
||||
startAngle = args[4]
|
||||
endAngle = args[5]
|
||||
circle.graphics.beginFill(args[3])
|
||||
.lineTo(0, 0)
|
||||
.lineTo(radius * Math.cos(startAngle), radius * Math.sin(endAngle))
|
||||
.arc(0, 0, radius, startAngle, endAngle)
|
||||
.lineTo(0, 0)
|
||||
circle.x = pos.x
|
||||
circle.y = pos.y
|
||||
circle.scaleY = @options.camera.y2x * 0.7
|
||||
|
|
|
@ -66,10 +66,10 @@ module.exports = class Mark extends CocoClass
|
|||
@mark = new createjs.Container()
|
||||
@mark.mouseChildren = false
|
||||
style = @sprite.thang.drawsBoundsStyle
|
||||
@drawsBoundsIndex = @sprite.thang.drawsBoundsIndex
|
||||
return if style is 'corner-text' and @sprite.thang.world.age is 0
|
||||
|
||||
# Confusingly make some semi-random colors that'll be consistent based on the drawsBoundsIndex
|
||||
@drawsBoundsIndex = @sprite.thang.drawsBoundsIndex
|
||||
colors = (128 + Math.floor(('0.'+Math.sin(3 * @drawsBoundsIndex + i).toString().substr(6)) * 128) for i in [1 ... 4])
|
||||
color = "rgba(#{colors[0]}, #{colors[1]}, #{colors[2]}, 0.5)"
|
||||
[w, h] = [@sprite.thang.width * Camera.PPM, @sprite.thang.height * Camera.PPM * @camera.y2x]
|
||||
|
|
|
@ -144,7 +144,7 @@ module.exports = class ThangState
|
|||
# We make sure the array keys won't collide with any string keys by using some unprintable characters.
|
||||
stringPieces = ['\x1D'] # Group Separator
|
||||
for element in value
|
||||
if element and element.isThang
|
||||
if element and element.id # Was checking element.isThang, but we can't store non-strings anyway
|
||||
element = element.id
|
||||
stringPieces.push element, '\x1E' # Record Separator(s)
|
||||
value = stringPieces.join('')
|
||||
|
|
|
@ -79,6 +79,13 @@ module.exports = class User extends CocoModel
|
|||
cache[idOrSlug] = user
|
||||
user
|
||||
|
||||
@getUnconflictedName: (name, done) ->
|
||||
$.ajax "/auth/name/#{name}",
|
||||
success: (data) -> done data.name
|
||||
statusCode: 409: (data) ->
|
||||
response = JSON.parse data.responseText
|
||||
done response.name
|
||||
|
||||
getEnabledEmails: ->
|
||||
@migrateEmails()
|
||||
emails = _.clone(@get('emails')) or {}
|
||||
|
|
|
@ -3,16 +3,23 @@
|
|||
|
||||
.row
|
||||
|
||||
|
||||
|
||||
.index-column, .documentation-column
|
||||
overflow-y: scroll
|
||||
overflow-x: hidden
|
||||
min-height: 600px
|
||||
|
||||
> ul
|
||||
padding: 0px 20px 20px 20px
|
||||
|
||||
.doc-name
|
||||
color: rgb(139, 69, 19)
|
||||
|
||||
|
||||
.documentation-column
|
||||
|
||||
.specialList
|
||||
list-style-type: none
|
||||
|
||||
.doc-description
|
||||
list-style-type: none
|
||||
|
|
|
@ -9,7 +9,7 @@ block content
|
|||
|
||||
else
|
||||
#save-button-container
|
||||
button.btn#save-button.disabled.secret(data-i18n="account_settings.autosave") Changes Save Automatically
|
||||
button.btn#save-button.disabled(data-i18n="general.save" disabled="true") No Changes
|
||||
|
||||
ul.nav.nav-pills#settings-tabs
|
||||
li
|
||||
|
@ -30,16 +30,19 @@ block content
|
|||
#general-pane.tab-pane
|
||||
p
|
||||
.form
|
||||
- var name = me.get('name') || '';
|
||||
- var email = me.get('email');
|
||||
- var admin = me.get('permissions').indexOf('admin') != -1;
|
||||
.form-group
|
||||
label.control-label(for="name", data-i18n="general.name") Name
|
||||
input#name.form-control(name="name", type="text", value="#{me.get('name') || ''}")
|
||||
input#name.form-control(name="name", type="text", value="#{name}")
|
||||
.form-group
|
||||
label.control-label(for="email", data-i18n="general.email") Email
|
||||
input#email.form-control(name="email", type="text", value="#{me.get('email')}")
|
||||
input#email.form-control(name="email", type="text", value="#{email}")
|
||||
if !isProduction
|
||||
.form-group.checkbox
|
||||
label(for="admin", data-i18n="account_settings.admin") Admin
|
||||
input#admin(name="admin", type="checkbox", checked=me.get('permissions').indexOf('admin') != -1)
|
||||
input#admin(name="admin", type="checkbox", checked=admin)
|
||||
|
||||
|
||||
#picture-pane.tab-pane
|
||||
|
|
|
@ -6,18 +6,25 @@ block content
|
|||
.col-xs-3.index-column.nano
|
||||
ul.nav.nav-list.list-group.nano-content
|
||||
for component in components
|
||||
li= component.get('name')
|
||||
ul
|
||||
each doc in component.attributes.propertyDocumentation
|
||||
a(href="##{component.get('name')}#{doc.name}")
|
||||
li
|
||||
| #{doc.name}
|
||||
a.doc-name(href="##{component.get('name')}")
|
||||
li= component.get('name')
|
||||
ul
|
||||
each doc in component.attributes.propertyDocumentation
|
||||
a(href="##{component.get('name')}#{doc.name}")
|
||||
li
|
||||
| #{doc.name}
|
||||
.col-xs-9.documentation-column.nano
|
||||
ul.nano-content
|
||||
for component in components
|
||||
each doc in component.attributes.propertyDocumentation
|
||||
li(id="#{component.get('name')}#{doc.name}")
|
||||
| #{doc.name}
|
||||
ul.specialList
|
||||
li=doc.description
|
||||
|
||||
li(id="#{component.get('name')}")
|
||||
| #{component.get('name')}
|
||||
ul
|
||||
li.doc-description
|
||||
| #{component.get('description')}
|
||||
ul
|
||||
each doc in component.attributes.propertyDocumentation
|
||||
li(id="#{component.get('name')}#{doc.name}")
|
||||
| #{doc.name}
|
||||
ul.specialList
|
||||
li!=marked(doc.description)
|
||||
|
|
@ -28,9 +28,10 @@ nav.navbar.navbar-default(role='navigation')
|
|||
span.glyphicon.glyphicon-eye-close
|
||||
span.spl Unwatch
|
||||
|
||||
li#patch-component-button
|
||||
a(data-i18n="common.submit_patch") Submit Patch
|
||||
if me.isAdmin()
|
||||
if !component.hasWriteAccess()
|
||||
li#patch-component-button
|
||||
a(data-i18n="common.submit_patch") Submit Patch
|
||||
if !me.get('anonymous')
|
||||
li#create-new-component-button
|
||||
a(data-i18n="editor.level_component_b_new") Create New Component
|
||||
|
||||
|
|
|
@ -34,6 +34,12 @@ block modal-body-content
|
|||
input#password.input-large.form-control(name="password", type="password", value=formValues.password)
|
||||
|
||||
if mode === 'signup'
|
||||
.form-group
|
||||
label.control-label(for="name", data-i18n="general.name") Name
|
||||
if me.get('name')
|
||||
input#name.input-large.form-control(name="name", type="text", value="#{me.get('name')}")
|
||||
else
|
||||
input#name.input-large.form-control(name="name", type="text", value="", placeholder="Anoner")
|
||||
.form-group.checkbox
|
||||
label.control-label(for="subscribe")
|
||||
input#subscribe(name="subscribe", type="checkbox", checked='checked')
|
||||
|
|
|
@ -11,17 +11,73 @@ JobProfileView = require './job_profile_view'
|
|||
module.exports = class SettingsView extends View
|
||||
id: 'account-settings-view'
|
||||
template: template
|
||||
changedFields: [] # DOM input fields
|
||||
|
||||
events:
|
||||
'click #save-button': 'save'
|
||||
'change #settings-panes input': 'save'
|
||||
'change #settings-panes input:checkbox': (e) -> @trigger 'checkboxToggled', e
|
||||
'keyup #settings-panes input:text, #settings-panes input:password': (e) -> @trigger 'inputChanged', e
|
||||
'keyup #name': 'onNameChange'
|
||||
'click #toggle-all-button': 'toggleEmailSubscriptions'
|
||||
'keypress #settings-panes': 'onKeyPress'
|
||||
|
||||
constructor: (options) ->
|
||||
@save = _.debounce(@save, 200)
|
||||
@onNameChange = _.debounce @checkNameExists, 500
|
||||
super options
|
||||
return unless me
|
||||
|
||||
@listenTo(me, 'invalid', (errors) -> forms.applyErrorsToForm(@$el, me.validationError))
|
||||
@on 'checkboxToggled', @onToggle
|
||||
@on 'checkboxToggled', @onInputChanged
|
||||
@on 'inputChanged', @onInputChanged
|
||||
@on 'enterPressed', @onEnter
|
||||
|
||||
onInputChanged: (e) ->
|
||||
return @enableSaveButton() unless e?.currentTarget
|
||||
that = e.currentTarget
|
||||
$that = $(that)
|
||||
savedValue = $that.data 'saved-value'
|
||||
currentValue = $that.val()
|
||||
if savedValue isnt currentValue
|
||||
@changedFields.push that unless that in @changedFields
|
||||
@enableSaveButton()
|
||||
else
|
||||
_.pull @changedFields, that
|
||||
@disableSaveButton() if _.isEmpty @changedFields
|
||||
|
||||
onToggle: (e) ->
|
||||
$that = $(e.currentTarget)
|
||||
$that.val $that[0].checked
|
||||
|
||||
onEnter: ->
|
||||
@save()
|
||||
|
||||
onKeyPress: (e) ->
|
||||
@trigger 'enterPressed', e if e.which is 13
|
||||
|
||||
enableSaveButton: ->
|
||||
$('#save-button', @$el).removeClass 'disabled'
|
||||
$('#save-button', @$el).removeClass 'btn-danger'
|
||||
$('#save-button', @$el).removeAttr 'disabled'
|
||||
$('#save-button', @$el).text 'Save'
|
||||
|
||||
disableSaveButton: ->
|
||||
$('#save-button', @$el).addClass 'disabled'
|
||||
$('#save-button', @$el).removeClass 'btn-danger'
|
||||
$('#save-button', @$el).attr 'disabled', "true"
|
||||
$('#save-button', @$el).text 'No Changes'
|
||||
|
||||
checkNameExists: =>
|
||||
name = $('#name', @$el).val()
|
||||
return if name is me.get 'name'
|
||||
User.getUnconflictedName name, (newName) =>
|
||||
forms.clearFormAlerts(@$el)
|
||||
if name is newName
|
||||
@suggestedName = undefined
|
||||
else
|
||||
@suggestedName = newName
|
||||
forms.setErrorToProperty @$el, 'name', "That name is taken! How about #{newName}?", true
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -50,6 +106,7 @@ module.exports = class SettingsView extends View
|
|||
super()
|
||||
if me.get('anonymous')
|
||||
@openModalView new AuthModalView()
|
||||
@updateSavedValues()
|
||||
|
||||
chooseTab: (category) ->
|
||||
id = "##{category}-pane"
|
||||
|
@ -98,7 +155,7 @@ module.exports = class SettingsView extends View
|
|||
@$el.find('.gravatar-fallback').toggle not me.get 'photoURL'
|
||||
|
||||
onPictureChanged: (e) =>
|
||||
@trigger 'change'
|
||||
@trigger 'inputChanged', e
|
||||
@$el.find('.gravatar-fallback').toggle not me.get 'photoURL'
|
||||
|
||||
save: (e) ->
|
||||
|
@ -122,7 +179,9 @@ module.exports = class SettingsView extends View
|
|||
errors = JSON.parse(res.responseText)
|
||||
forms.applyErrorsToForm(@$el, errors)
|
||||
save.text($.i18n.t('account_settings.error_saving', defaultValue: 'Error Saving')).removeClass('btn-success').addClass('btn-danger', 500)
|
||||
res.success (model, response, options) ->
|
||||
res.success (model, response, options) =>
|
||||
@changedFields = []
|
||||
@updateSavedValues()
|
||||
save.text($.i18n.t('account_settings.saved', defaultValue: 'Changes Saved')).removeClass('btn-success', 500)
|
||||
|
||||
grabData: ->
|
||||
|
@ -142,6 +201,7 @@ module.exports = class SettingsView extends View
|
|||
me.set('password', password1)
|
||||
|
||||
grabOtherData: ->
|
||||
$('#name', @$el).val @suggestedName if @suggestedName
|
||||
me.set 'name', $('#name', @$el).val()
|
||||
me.set 'email', $('#email', @$el).val()
|
||||
for emailName, enabled of @getSubscriptions()
|
||||
|
@ -162,3 +222,9 @@ module.exports = class SettingsView extends View
|
|||
if updated
|
||||
jobProfile.updated = (new Date()).toISOString()
|
||||
me.set 'jobProfile', jobProfile
|
||||
|
||||
updateSavedValues: ->
|
||||
$('#settings-panes input:text').each ->
|
||||
$(@).data 'saved-value', $(@).val()
|
||||
$('#settings-panes input:checkbox').each ->
|
||||
$(@).data 'saved-value', JSON.stringify $(@)[0].checked
|
||||
|
|
|
@ -24,4 +24,5 @@ module.exports = class UnnamedView extends RootView
|
|||
getRenderData: ->
|
||||
c = super()
|
||||
c.components = @componentDocs.models
|
||||
c.marked = marked
|
||||
c
|
||||
|
|
|
@ -31,6 +31,9 @@ module.exports = class DeltaView extends CocoView
|
|||
|
||||
for modelName in ['model', 'headModel', 'comparisonModel']
|
||||
@[modelName] = options[modelName]
|
||||
continue unless @[modelName]
|
||||
if not @[modelName].isLoaded
|
||||
@[modelName] = @supermodel.loadModel(@[modelName], 'document').model
|
||||
|
||||
@buildDeltas() if @supermodel.finished()
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ module.exports = class PatchModal extends ModalView
|
|||
template: template
|
||||
plain: true
|
||||
modalWidthPercent: 60
|
||||
@DOC_SKIP_PATHS = ['_id','version', 'commitMessage', 'parent', 'created', 'slug', 'index', '__v', 'patches', 'creator']
|
||||
@DOC_SKIP_PATHS = ['_id','version', 'commitMessage', 'parent', 'created', 'slug', 'index', '__v', 'patches', 'creator', 'js']
|
||||
|
||||
events:
|
||||
'click #withdraw-button': 'withdrawPatch'
|
||||
|
|
|
@ -285,7 +285,7 @@ module.exports = class ThangTypeEditView extends View
|
|||
@scale = scaleValue
|
||||
@$el.find('.scale-label').text " #{fixed}x "
|
||||
if @currentSprite
|
||||
@currentSprite.scaleFactor = scaleValue
|
||||
@currentSprite.scaleFactorX = @currentSprite.scaleFactorY = scaleValue
|
||||
@currentSprite.updateScale()
|
||||
else if @currentObject?
|
||||
@currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue
|
||||
|
|
|
@ -15,11 +15,16 @@ module.exports = class AuthModalView extends View
|
|||
'click #switch-to-signup-button': 'onSignupInstead'
|
||||
'click #signup-confirm-age': 'checkAge'
|
||||
'submit': 'onSubmitForm' # handles both submit buttons
|
||||
'keyup #name': 'onNameChange'
|
||||
|
||||
subscriptions:
|
||||
'server-error': 'onServerError'
|
||||
'logging-in-with-facebook': 'onLoggingInWithFacebook'
|
||||
|
||||
constructor: (options) ->
|
||||
@onNameChange = _.debounce @checkNameExists, 500
|
||||
super options
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.showRequiredError = @options.showRequiredError
|
||||
|
@ -31,6 +36,7 @@ module.exports = class AuthModalView extends View
|
|||
c.mode = @mode
|
||||
c.formValues = @previousFormInputs or {}
|
||||
c.onEmployersPage = Backbone.history.fragment is "employers"
|
||||
c.me = me
|
||||
c
|
||||
|
||||
afterInsert: ->
|
||||
|
@ -64,6 +70,8 @@ module.exports = class AuthModalView extends View
|
|||
userObject = forms.formToObject @$el
|
||||
delete userObject.subscribe
|
||||
delete userObject['confirm-age']
|
||||
delete userObject.name if userObject.name is ''
|
||||
userObject.name = @suggestedName if @suggestedName
|
||||
for key, val of me.attributes when key in ['preferredLanguage', 'testGroupNumber', 'dateCreated', 'wizardColor1', 'name', 'music', 'volume', 'emails']
|
||||
userObject[key] ?= val
|
||||
subscribe = @$el.find('#signup-subscribe').prop('checked')
|
||||
|
@ -82,3 +90,14 @@ module.exports = class AuthModalView extends View
|
|||
|
||||
onServerError: (e) -> # TODO: work error handling into a separate forms system
|
||||
@disableModalInProgress(@$el)
|
||||
|
||||
checkNameExists: =>
|
||||
name = $('#name', @$el).val()
|
||||
return forms.clearFormAlerts(@$el) if name is ''
|
||||
User.getUnconflictedName name, (newName) =>
|
||||
forms.clearFormAlerts(@$el)
|
||||
if name is newName
|
||||
@suggestedName = undefined
|
||||
else
|
||||
@suggestedName = newName
|
||||
forms.setErrorToProperty @$el, 'name', "That name is taken! How about #{newName}?", true
|
||||
|
|
|
@ -4,20 +4,22 @@ WizardSprite = require 'lib/surface/WizardSprite'
|
|||
ThangType = require 'models/ThangType'
|
||||
{me} = require 'lib/auth'
|
||||
forms = require 'lib/forms'
|
||||
User = require 'models/User'
|
||||
|
||||
module.exports = class WizardSettingsModal extends View
|
||||
id: 'wizard-settings-modal'
|
||||
template: template
|
||||
closesOnClickOutside: false
|
||||
|
||||
events:
|
||||
'keyup #wizard-settings-name': -> @trigger 'nameChanged'
|
||||
'click #wizard-settings-done': 'onWizardSettingsDone'
|
||||
|
||||
constructor: (options) ->
|
||||
@onNameChange = _.debounce(@checkNameExists, 500)
|
||||
@on 'nameChanged', @onNameChange
|
||||
super options
|
||||
|
||||
events:
|
||||
'keyup #wizard-settings-name': 'onNameChange'
|
||||
'click #wizard-settings-done': 'onWizardSettingsDone'
|
||||
|
||||
afterRender: ->
|
||||
WizardSettingsView = require 'views/account/wizard_settings_view'
|
||||
view = new WizardSettingsView()
|
||||
|
@ -27,10 +29,10 @@ module.exports = class WizardSettingsModal extends View
|
|||
checkNameExists: =>
|
||||
forms.clearFormAlerts(@$el)
|
||||
name = $('#wizard-settings-name').val()
|
||||
success = (id) =>
|
||||
User.getUnconflictedName name, (newName) =>
|
||||
forms.clearFormAlerts(@$el)
|
||||
forms.applyErrorsToForm(@$el, {property: 'name', message: 'is already taken'}) if id and id isnt me.id
|
||||
$.ajax("/db/user/#{name}/nameToID", {success: success})
|
||||
if name isnt newName
|
||||
forms.setErrorToProperty @$el, 'name', 'This name is already taken so you won\'t be able to keep it.', true
|
||||
|
||||
onWizardSettingsDone: ->
|
||||
me.set('name', $('#wizard-settings-name').val())
|
||||
|
|
|
@ -368,7 +368,7 @@ module.exports = class SpellView extends View
|
|||
# Now that that's figured out, perform the update.
|
||||
# The web worker Aether won't track state, so don't have to worry about updating it
|
||||
finishUpdatingAether = (aether) =>
|
||||
@displayAether aether
|
||||
@displayAether aether, codeIsAsCast
|
||||
@lastUpdatedAetherSpellThang = @spellThang
|
||||
@guessWhetherFinished aether if fromCodeChange
|
||||
|
||||
|
@ -396,10 +396,9 @@ module.exports = class SpellView extends View
|
|||
@aceSession.setAnnotations []
|
||||
@highlightCurrentLine {} # This'll remove all highlights
|
||||
|
||||
displayAether: (aether) ->
|
||||
displayAether: (aether, isCast=false) ->
|
||||
@displayedAether = aether
|
||||
isCast = not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'}
|
||||
isCast = isCast or @spell.language isnt 'javascript' # Since we don't have linting for other languages
|
||||
isCast = isCast or not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'}
|
||||
problem.destroy() for problem in @problems # Just in case another problem was added since clearAetherDisplay() ran.
|
||||
@problems = []
|
||||
annotations = []
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
"nodemon": "0.7.5",
|
||||
"marked": "0.2.x",
|
||||
"telepath-brunch": "https://github.com/nwinter/telepath-brunch/tarball/master",
|
||||
"bower": "~1.2.8",
|
||||
"bower": "~1.3.8",
|
||||
"bless-brunch": "~1.6.1",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"karma-chrome-launcher": "~0.1.2",
|
||||
|
|
|
@ -157,13 +157,30 @@ module.exports.setup = (app) ->
|
|||
res.send msg + '<p><a href="/account/settings">Account settings</a></p>'
|
||||
res.end()
|
||||
|
||||
app.get '/auth/name/?*', (req, res) ->
|
||||
parts = req.path.split '/'
|
||||
console.log parts
|
||||
originalName = parts[3]
|
||||
|
||||
return errors.badInput res, 'No name provided.' unless originalName and originalName isnt ''
|
||||
return errors.notFound res if parts.length isnt 4
|
||||
|
||||
User.unconflictName originalName, (err, name) ->
|
||||
return errors.serverError res, err if err
|
||||
response = name: name
|
||||
if originalName is name
|
||||
res.send 200, response
|
||||
else
|
||||
errors.conflict res, response
|
||||
|
||||
|
||||
module.exports.loginUser = loginUser = (req, res, user, send=true, next=null) ->
|
||||
user.save((err) ->
|
||||
return errors.serverError res, err if err?
|
||||
|
||||
req.logIn(user, (err) ->
|
||||
return errors.serverError res, err if err?
|
||||
return res.send user if send
|
||||
return res.send(user) and res.end() if send
|
||||
next() if next
|
||||
)
|
||||
)
|
||||
|
|
32
test/demo/views/modals/WizardSettingsModal.demo.coffee
Normal file
32
test/demo/views/modals/WizardSettingsModal.demo.coffee
Normal file
File diff suppressed because one or more lines are too long
|
@ -152,3 +152,27 @@ describe '/auth/unsubscribe', ->
|
|||
expect(user.get('emails').recruitNotes.enabled).toBe(false)
|
||||
expect(user.isEmailSubscriptionEnabled('generalNews')).toBeTruthy()
|
||||
done()
|
||||
|
||||
describe '/auth/name', ->
|
||||
url = '/auth/name'
|
||||
|
||||
it 'must provide a name to check with', (done) ->
|
||||
request.get {url: getURL(url + '/'), json: {}}, (err, response) ->
|
||||
expect(err).toBeNull()
|
||||
expect(response.statusCode).toBe 422
|
||||
done()
|
||||
|
||||
it 'can GET a non-conflicting name', (done) ->
|
||||
request.get {url: getURL(url + '/Gandalf'), json: {}}, (err, response) ->
|
||||
expect(err).toBeNull()
|
||||
expect(response.statusCode).toBe 200
|
||||
expect(response.body.name).toBe 'Gandalf'
|
||||
done()
|
||||
|
||||
it 'can GET a new name in case of conflict', (done) ->
|
||||
request.get {url: getURL(url + '/joe'), json: {}}, (err, response) ->
|
||||
expect(err).toBeNull()
|
||||
expect(response.statusCode).toBe 409
|
||||
expect(response.body.name).not.toBe 'joe'
|
||||
expect(response.body.name.length).toBe 4 # 'joe' and a random number
|
||||
done()
|
||||
|
|
Loading…
Reference in a new issue