Merge branch 'master' of https://github.com/codecombat/codecombat
This commit is contained in:
commit
2a3cecb118
20 changed files with 116 additions and 113 deletions
app
lib
models
schemas/models
templates
views
server/users
|
@ -116,7 +116,7 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
flagThang = thangType: '53fa25f25bc220000052c2be', id: 'Placeholder Flag', components: []
|
flagThang = thangType: '53fa25f25bc220000052c2be', id: 'Placeholder Flag', components: []
|
||||||
for thang in (@level.get('thangs') or []).concat [flagThang]
|
for thang in (@level.get('thangs') or []).concat [flagThang]
|
||||||
thangIDs.push thang.thangType
|
thangIDs.push thang.thangType
|
||||||
@loadItemThangsEquippedByLevelThang(thang)
|
@loadThangsRequiredByLevelThang(thang)
|
||||||
for comp in thang.components or []
|
for comp in thang.components or []
|
||||||
componentVersions.push _.pick(comp, ['original', 'majorVersion'])
|
componentVersions.push _.pick(comp, ['original', 'majorVersion'])
|
||||||
|
|
||||||
|
@ -160,23 +160,27 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
|
|
||||||
@worldNecessities = @worldNecessities.concat worldNecessities
|
@worldNecessities = @worldNecessities.concat worldNecessities
|
||||||
|
|
||||||
loadItemThangsEquippedByLevelThang: (levelThang) ->
|
loadThangsRequiredByLevelThang: (levelThang) ->
|
||||||
@loadItemThangsFromComponentList levelThang.components
|
@loadThangsRequiredFromComponentList levelThang.components
|
||||||
|
|
||||||
loadItemThangsEquippedByThangType: (thangType) ->
|
loadThangsRequiredByThangType: (thangType) ->
|
||||||
@loadItemThangsFromComponentList thangType.get('components')
|
@loadThangsRequiredFromComponentList thangType.get('components')
|
||||||
|
|
||||||
loadItemThangsFromComponentList: (components) ->
|
loadThangsRequiredFromComponentList: (components) ->
|
||||||
equipsThangComponent = _.find components, (c) -> c.original is LevelComponent.EquipsID
|
requiredThangTypes = []
|
||||||
inventory = equipsThangComponent?.config?.inventory
|
for component in components when component.config
|
||||||
for itemThangType in _.values inventory
|
if component.original is LevelComponent.EquipsID
|
||||||
url = "/db/thang.type/#{itemThangType}/version?project=name,components,original"
|
requiredThangTypes.push itemThangType for itemThangType in _.values (component.config.inventory ? {})
|
||||||
|
else if component.config.requiredThangTypes
|
||||||
|
requiredThangTypes = requiredThangTypes.concat component.config.requiredThangTypes
|
||||||
|
for thangType in requiredThangTypes
|
||||||
|
url = "/db/thang.type/#{thangType}/version?project=name,components,original"
|
||||||
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
@worldNecessities.push @maybeLoadURL(url, ThangType, 'thang')
|
||||||
|
|
||||||
onThangNamesLoaded: (thangNames) ->
|
onThangNamesLoaded: (thangNames) ->
|
||||||
for thangType in thangNames.models
|
for thangType in thangNames.models
|
||||||
@loadDefaultComponentsForThangType(thangType)
|
@loadDefaultComponentsForThangType(thangType)
|
||||||
@loadItemThangsEquippedByThangType(thangType)
|
@loadThangsRequiredByThangType(thangType)
|
||||||
|
|
||||||
loadDefaultComponentsForThangType: (thangType) ->
|
loadDefaultComponentsForThangType: (thangType) ->
|
||||||
return unless components = thangType.get('components')
|
return unless components = thangType.get('components')
|
||||||
|
@ -188,7 +192,7 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
index = @worldNecessities.indexOf(resource)
|
index = @worldNecessities.indexOf(resource)
|
||||||
if resource.name is 'thang'
|
if resource.name is 'thang'
|
||||||
@loadDefaultComponentsForThangType(resource.model)
|
@loadDefaultComponentsForThangType(resource.model)
|
||||||
@loadItemThangsEquippedByThangType(resource.model)
|
@loadThangsRequiredByThangType(resource.model)
|
||||||
|
|
||||||
return unless index >= 0
|
return unless index >= 0
|
||||||
@worldNecessities.splice(index, 1)
|
@worldNecessities.splice(index, 1)
|
||||||
|
|
|
@ -31,7 +31,7 @@ module.exports.applyErrorsToForm = (el, errors, warning=false) ->
|
||||||
module.exports.setErrorToField = setErrorToField = (el, message, warning=false) ->
|
module.exports.setErrorToField = setErrorToField = (el, message, warning=false) ->
|
||||||
formGroup = el.closest('.form-group')
|
formGroup = el.closest('.form-group')
|
||||||
unless formGroup.length
|
unless formGroup.length
|
||||||
return console.error "#{el} did not contain a form group"
|
return console.error el, " did not contain a form group, so couldn't show message:", message
|
||||||
|
|
||||||
kind = if warning then 'warning' else 'error'
|
kind = if warning then 'warning' else 'error'
|
||||||
formGroup.addClass "has-#{kind}"
|
formGroup.addClass "has-#{kind}"
|
||||||
|
@ -40,7 +40,7 @@ module.exports.setErrorToField = setErrorToField = (el, message, warning=false)
|
||||||
module.exports.setErrorToProperty = setErrorToProperty = (el, property, message, warning=false) ->
|
module.exports.setErrorToProperty = setErrorToProperty = (el, property, message, warning=false) ->
|
||||||
input = $("[name='#{property}']", el)
|
input = $("[name='#{property}']", el)
|
||||||
unless input.length
|
unless input.length
|
||||||
return console.error "#{property} not found in #{el}"
|
return console.error "#{property} not found in", el, "so couldn't show message:", message
|
||||||
|
|
||||||
setErrorToField input, message, warning
|
setErrorToField input, message, warning
|
||||||
|
|
||||||
|
|
|
@ -51,16 +51,16 @@ class CocoModel extends Backbone.Model
|
||||||
@loadFromBackup()
|
@loadFromBackup()
|
||||||
|
|
||||||
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
||||||
|
|
||||||
attributesWithDefaults: undefined
|
attributesWithDefaults: undefined
|
||||||
|
|
||||||
get: (attribute, withDefault=false) ->
|
get: (attribute, withDefault=false) ->
|
||||||
if withDefault
|
if withDefault
|
||||||
if @attributesWithDefaults is undefined then @buildAttributesWithDefaults()
|
if @attributesWithDefaults is undefined then @buildAttributesWithDefaults()
|
||||||
return @attributesWithDefaults[attribute]
|
return @attributesWithDefaults[attribute]
|
||||||
else
|
else
|
||||||
super(attribute)
|
super(attribute)
|
||||||
|
|
||||||
set: ->
|
set: ->
|
||||||
delete @attributesWithDefaults
|
delete @attributesWithDefaults
|
||||||
inFlux = @loading or not @loaded
|
inFlux = @loading or not @loaded
|
||||||
|
@ -180,13 +180,13 @@ class CocoModel extends Backbone.Model
|
||||||
clone
|
clone
|
||||||
|
|
||||||
isPublished: ->
|
isPublished: ->
|
||||||
for permission in @get('permissions') or []
|
for permission in (@get('permissions', true) ? [])
|
||||||
return true if permission.target is 'public' and permission.access is 'read'
|
return true if permission.target is 'public' and permission.access is 'read'
|
||||||
false
|
false
|
||||||
|
|
||||||
publish: ->
|
publish: ->
|
||||||
if @isPublished() then throw new Error('Can\'t publish what\'s already-published. Can\'t kill what\'s already dead.')
|
if @isPublished() then throw new Error('Can\'t publish what\'s already-published. Can\'t kill what\'s already dead.')
|
||||||
@set 'permissions', (@get('permissions') or []).concat({access: 'read', target: 'public'})
|
@set 'permissions', @get('permissions', true).concat({access: 'read', target: 'public'})
|
||||||
|
|
||||||
@isObjectID: (s) ->
|
@isObjectID: (s) ->
|
||||||
s.length is 24 and s.match(/[a-f0-9]/gi)?.length is 24
|
s.length is 24 and s.match(/[a-f0-9]/gi)?.length is 24
|
||||||
|
@ -195,10 +195,9 @@ class CocoModel extends Backbone.Model
|
||||||
# actor is a User object
|
# actor is a User object
|
||||||
actor ?= me
|
actor ?= me
|
||||||
return true if actor.isAdmin()
|
return true if actor.isAdmin()
|
||||||
if @get('permissions')?
|
for permission in (@get('permissions', true) ? [])
|
||||||
for permission in @get('permissions')
|
if permission.target is 'public' or actor.get('_id') is permission.target
|
||||||
if permission.target is 'public' or actor.get('_id') is permission.target
|
return true if permission.access in ['owner', 'read']
|
||||||
return true if permission.access in ['owner', 'read']
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
@ -206,16 +205,14 @@ class CocoModel extends Backbone.Model
|
||||||
# actor is a User object
|
# actor is a User object
|
||||||
actor ?= me
|
actor ?= me
|
||||||
return true if actor.isAdmin()
|
return true if actor.isAdmin()
|
||||||
if @get('permissions')?
|
for permission in (@get('permissions', true) ? [])
|
||||||
for permission in @get('permissions')
|
if permission.target is 'public' or actor.get('_id') is permission.target
|
||||||
if permission.target is 'public' or actor.get('_id') is permission.target
|
return true if permission.access in ['owner', 'write']
|
||||||
return true if permission.access in ['owner', 'write']
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
getOwner: ->
|
getOwner: ->
|
||||||
return null unless permissions = @get 'permissions'
|
ownerPermission = _.find @get('permissions', true), access: 'owner'
|
||||||
ownerPermission = _.find permissions, access: 'owner'
|
|
||||||
ownerPermission?.target
|
ownerPermission?.target
|
||||||
|
|
||||||
getDelta: ->
|
getDelta: ->
|
||||||
|
|
|
@ -13,7 +13,7 @@ module.exports = class LevelSession extends CocoModel
|
||||||
@set('state', state)
|
@set('state', state)
|
||||||
|
|
||||||
updatePermissions: ->
|
updatePermissions: ->
|
||||||
permissions = @get 'permissions'
|
permissions = @get 'permissions', true
|
||||||
permissions = (p for p in permissions when p.target isnt 'public')
|
permissions = (p for p in permissions when p.target isnt 'public')
|
||||||
if @get('multiplayer')
|
if @get('multiplayer')
|
||||||
permissions.push {target: 'public', access: 'write'}
|
permissions.push {target: 'public', access: 'write'}
|
||||||
|
|
|
@ -13,10 +13,7 @@ module.exports = class User extends CocoModel
|
||||||
CocoModel.pollAchievements() # Check for achievements on login
|
CocoModel.pollAchievements() # Check for achievements on login
|
||||||
super arguments...
|
super arguments...
|
||||||
|
|
||||||
isAdmin: ->
|
isAdmin: -> 'admin' in @get('permissions', true)
|
||||||
permissions = @attributes['permissions'] or []
|
|
||||||
return 'admin' in permissions
|
|
||||||
|
|
||||||
isAnonymous: -> @get('anonymous', true)
|
isAnonymous: -> @get('anonymous', true)
|
||||||
displayName: -> @get('name', true)
|
displayName: -> @get('name', true)
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ _.extend LevelComponentSchema.properties,
|
||||||
format: 'hidden'
|
format: 'hidden'
|
||||||
dependencies: c.array {title: 'Dependencies', description: 'An array of Components upon which this Component depends.', uniqueItems: true}, DependencySchema
|
dependencies: c.array {title: 'Dependencies', description: 'An array of Components upon which this Component depends.', uniqueItems: true}, DependencySchema
|
||||||
propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this Component will add to its Thang which other Components might want to also use.'}, PropertyDocumentationSchema
|
propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this Component will add to its Thang which other Components might want to also use.'}, PropertyDocumentationSchema
|
||||||
configSchema: _.extend metaschema, {title: 'Configuration Schema', description: 'A schema for validating the arguments that can be passed to this Component as configuration.', default: {type: 'object', additionalProperties: false}}
|
configSchema: _.extend metaschema, {title: 'Configuration Schema', description: 'A schema for validating the arguments that can be passed to this Component as configuration.', default: {type: 'object'}}
|
||||||
official:
|
official:
|
||||||
type: 'boolean'
|
type: 'boolean'
|
||||||
title: 'Official'
|
title: 'Official'
|
||||||
|
|
|
@ -32,7 +32,7 @@ block content
|
||||||
.form
|
.form
|
||||||
- var name = me.get('name') || '';
|
- var name = me.get('name') || '';
|
||||||
- var email = me.get('email');
|
- var email = me.get('email');
|
||||||
- var admin = me.get('permissions').indexOf('admin') != -1;
|
- var admin = me.get('permissions', true).indexOf('admin') != -1;
|
||||||
.form-group
|
.form-group
|
||||||
label.control-label(for="name", data-i18n="general.name") Name
|
label.control-label(for="name", data-i18n="general.name") Name
|
||||||
input#name.form-control(name="name", type="text", value="#{name}")
|
input#name.form-control(name="name", type="text", value="#{name}")
|
||||||
|
|
|
@ -67,7 +67,7 @@ body
|
||||||
.footer.clearfix
|
.footer.clearfix
|
||||||
.content
|
.content
|
||||||
p.footer-link-text
|
p.footer-link-text
|
||||||
if pathname == "/" || (me.get('permissions') || []).indexOf('employer') != -1
|
if pathname == "/" || (me.get('permissions', true)).indexOf('employer') != -1
|
||||||
a(href='/employers', title='Home', tabindex=-1, data-i18n="nav.employers") Employers
|
a(href='/employers', title='Home', tabindex=-1, data-i18n="nav.employers") Employers
|
||||||
else
|
else
|
||||||
a(href='/', title='Home', tabindex=-1, data-i18n="nav.home") Home
|
a(href='/', title='Home', tabindex=-1, data-i18n="nav.home") Home
|
||||||
|
|
|
@ -197,9 +197,7 @@ module.exports = class EmployersView extends RootView
|
||||||
ctx.numberOfCandidates = ctx.featuredCandidates.length
|
ctx.numberOfCandidates = ctx.featuredCandidates.length
|
||||||
ctx
|
ctx
|
||||||
|
|
||||||
isEmployer: ->
|
isEmployer: -> 'employer' in me.get('permissions', true)
|
||||||
userPermissions = me.get('permissions') ? []
|
|
||||||
_.contains userPermissions, 'employer'
|
|
||||||
|
|
||||||
setUpScrolling: =>
|
setUpScrolling: =>
|
||||||
$('.nano').nanoScroller()
|
$('.nano').nanoScroller()
|
||||||
|
@ -209,7 +207,7 @@ module.exports = class EmployersView extends RootView
|
||||||
# $('.nano').nanoScroller({scrollTo: $(window.location.hash)})
|
# $('.nano').nanoScroller({scrollTo: $(window.location.hash)})
|
||||||
|
|
||||||
checkForEmployerSignupHash: =>
|
checkForEmployerSignupHash: =>
|
||||||
if window.location.hash is '#employerSignupLoggingIn' and not ('employer' in me.get('permissions')) and not me.isAdmin()
|
if window.location.hash is '#employerSignupLoggingIn' and not ('employer' in me.get('permissions', true)) and not me.isAdmin()
|
||||||
@openModalView new EmployerSignupModal
|
@openModalView new EmployerSignupModal
|
||||||
window.location.hash = ''
|
window.location.hash = ''
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ module.exports = class JobProfileTreemaView extends CocoView
|
||||||
{name: 'Provide your name.', weight: 1, fn: modified 'name'}
|
{name: 'Provide your name.', weight: 1, fn: modified 'name'}
|
||||||
{name: 'Choose your city.', weight: 1, fn: modified 'city'}
|
{name: 'Choose your city.', weight: 1, fn: modified 'city'}
|
||||||
{name: 'Pick your country.', weight: 0, fn: exists 'country'}
|
{name: 'Pick your country.', weight: 0, fn: exists 'country'}
|
||||||
{name: 'List at least five skills.', weight: 2, fn: -> jobProfile.skills.length >= 5}
|
{name: 'List at least five skills.', weight: 2, fn: -> jobProfile.skills?.length >= 5}
|
||||||
{name: 'Write a short description to summarize yourself at a glance.', weight: 2, fn: modified 'shortDescription'}
|
{name: 'Write a short description to summarize yourself at a glance.', weight: 2, fn: modified 'shortDescription'}
|
||||||
{name: 'Fill in your main description to sell yourself and describe the work you\'re looking for.', weight: 3, fn: modified 'longDescription'}
|
{name: 'Fill in your main description to sell yourself and describe the work you\'re looking for.', weight: 3, fn: modified 'longDescription'}
|
||||||
{name: 'List your work experience.', weight: 3, fn: listStarted 'work', ['role', 'employer']}
|
{name: 'List your work experience.', weight: 3, fn: listStarted 'work', ['role', 'employer']}
|
||||||
|
@ -95,7 +95,7 @@ module.exports = class JobProfileTreemaView extends CocoView
|
||||||
getData: ->
|
getData: ->
|
||||||
return {} unless me.get('jobProfile') or @hasEditedProfile
|
return {} unless me.get('jobProfile') or @hasEditedProfile
|
||||||
_.pick @jobProfileTreema.data, (value, key) => key in @editableSettings
|
_.pick @jobProfileTreema.data, (value, key) => key in @editableSettings
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@jobProfileTreema?.destroy()
|
@jobProfileTreema?.destroy()
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -52,9 +52,7 @@ module.exports = class CandidatesView extends RootView
|
||||||
ctx._ = _
|
ctx._ = _
|
||||||
ctx
|
ctx
|
||||||
|
|
||||||
isEmployer: ->
|
isEmployer: -> 'employer' in me.get('permissions', true)
|
||||||
userPermissions = me.get('permissions') ? []
|
|
||||||
_.contains userPermissions, "employer"
|
|
||||||
|
|
||||||
setUpScrolling: ->
|
setUpScrolling: ->
|
||||||
$(".nano").nanoScroller()
|
$(".nano").nanoScroller()
|
||||||
|
@ -64,9 +62,9 @@ module.exports = class CandidatesView extends RootView
|
||||||
$(".nano").nanoScroller({scrollTo:$(window.location.hash)})
|
$(".nano").nanoScroller({scrollTo:$(window.location.hash)})
|
||||||
|
|
||||||
checkForEmployerSignupHash: =>
|
checkForEmployerSignupHash: =>
|
||||||
if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get("permissions"))
|
if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get('permissions', true))
|
||||||
@openModalView new EmployerSignupModal
|
@openModalView new EmployerSignupModal
|
||||||
window.location.hash = ""
|
window.location.hash = ''
|
||||||
|
|
||||||
sortTable: ->
|
sortTable: ->
|
||||||
# http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html
|
# http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html
|
||||||
|
|
|
@ -31,7 +31,7 @@ module.exports = class ForkModal extends ModalView
|
||||||
newModel.unset 'parent'
|
newModel.unset 'parent'
|
||||||
newModel.set 'commitMessage', "Forked from #{@model.get('name')}"
|
newModel.set 'commitMessage', "Forked from #{@model.get('name')}"
|
||||||
newModel.set 'name', @$el.find('#fork-model-name').val()
|
newModel.set 'name', @$el.find('#fork-model-name').val()
|
||||||
if @model.get 'permissions'
|
if @model.schema.properties.permissions
|
||||||
newModel.set 'permissions', [access: 'owner', target: me.id]
|
newModel.set 'permissions', [access: 'owner', target: me.id]
|
||||||
newPathPrefix = "editor/#{@editorPath}/"
|
newPathPrefix = "editor/#{@editorPath}/"
|
||||||
res = newModel.save()
|
res = newModel.save()
|
||||||
|
|
|
@ -30,7 +30,7 @@ module.exports = class ThangComponentConfigView extends CocoView
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
@buildTreema()
|
@buildTreema()
|
||||||
|
|
||||||
setConfig: (config) ->
|
setConfig: (config) ->
|
||||||
@handlingChange = true
|
@handlingChange = true
|
||||||
@editThangTreema.set('/', config)
|
@editThangTreema.set('/', config)
|
||||||
|
@ -51,7 +51,7 @@ module.exports = class ThangComponentConfigView extends CocoView
|
||||||
schema = $.extend true, {}, @component.get('configSchema')
|
schema = $.extend true, {}, @component.get('configSchema')
|
||||||
schema.default ?= {}
|
schema.default ?= {}
|
||||||
_.merge schema.default, @additionalDefaults if @additionalDefaults
|
_.merge schema.default, @additionalDefaults if @additionalDefaults
|
||||||
|
|
||||||
if @level?.get('type') is 'hero'
|
if @level?.get('type') is 'hero'
|
||||||
schema.required = []
|
schema.required = []
|
||||||
treemaOptions =
|
treemaOptions =
|
||||||
|
@ -77,6 +77,7 @@ module.exports = class ThangComponentConfigView extends CocoView
|
||||||
'seconds': nodes.SecondsNode
|
'seconds': nodes.SecondsNode
|
||||||
'speed': nodes.SpeedNode
|
'speed': nodes.SpeedNode
|
||||||
'acceleration': nodes.AccelerationNode
|
'acceleration': nodes.AccelerationNode
|
||||||
|
'thang-type': nodes.ThangTypeNode
|
||||||
'item-thang-type': nodes.ItemThangTypeNode
|
'item-thang-type': nodes.ItemThangTypeNode
|
||||||
|
|
||||||
@editThangTreema = @$el.find('.treema').treema treemaOptions
|
@editThangTreema = @$el.find('.treema').treema treemaOptions
|
||||||
|
@ -92,7 +93,7 @@ module.exports = class ThangComponentConfigView extends CocoView
|
||||||
@trigger 'changed', { component: @component, config: @config }
|
@trigger 'changed', { component: @component, config: @config }
|
||||||
|
|
||||||
data: -> @editThangTreema.data
|
data: -> @editThangTreema.data
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@editThangTreema?.destroy()
|
@editThangTreema?.destroy()
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -33,16 +33,16 @@ module.exports = class LevelFeedbackView extends CocoView
|
||||||
|
|
||||||
getRenderData: (context={}) ->
|
getRenderData: (context={}) ->
|
||||||
context = super(context)
|
context = super(context)
|
||||||
|
context.moment = moment
|
||||||
|
context.allFeedback = []
|
||||||
|
context.averageRating = 0
|
||||||
|
context.totalRatings = 0
|
||||||
if @allFeedback
|
if @allFeedback
|
||||||
context.allFeedback = (m.attributes for m in @allFeedback.models when @allFeedback.models.length < 20 or m.get('review'))
|
context.allFeedback = (m.attributes for m in @allFeedback.models when @allFeedback.models.length < 20 or m.get('review'))
|
||||||
context.averageRating = _.reduce((m.get('rating') for m in @allFeedback.models), (acc, x) -> acc + (x ? 5)) / (@allFeedback.models.length or 1)
|
context.averageRating = _.reduce((m.get('rating') for m in @allFeedback.models), (acc, x) -> acc + (x ? 5)) / (@allFeedback.models.length)
|
||||||
context.totalRatings = @allFeedback.models.length
|
context.totalRatings = @allFeedback.models.length
|
||||||
else
|
else
|
||||||
context.allFeedback = []
|
|
||||||
context.averageRating = 0
|
|
||||||
context.totalRatings = 0
|
|
||||||
context.loading = true
|
context.loading = true
|
||||||
context.moment = moment
|
|
||||||
context
|
context
|
||||||
|
|
||||||
onViewSwitched: (e) ->
|
onViewSwitched: (e) ->
|
||||||
|
|
|
@ -200,6 +200,9 @@ module.exports.AccelerationNode = class AccelerationNode extends TreemaNode.node
|
||||||
|
|
||||||
module.exports.ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.string
|
module.exports.ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.string
|
||||||
valueClass: 'treema-thang-type'
|
valueClass: 'treema-thang-type'
|
||||||
|
@thangTypes: null
|
||||||
|
@thangTypesCollection: null
|
||||||
|
|
||||||
constructor: (args...) ->
|
constructor: (args...) ->
|
||||||
super args...
|
super args...
|
||||||
data = @getData()
|
data = @getData()
|
||||||
|
@ -223,63 +226,68 @@ module.exports.ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.st
|
||||||
else
|
else
|
||||||
@data = null
|
@data = null
|
||||||
|
|
||||||
module.exports.ItemThangTypeNode = ItemThangTypeNode = class ItemThangTypeNode extends TreemaNode.nodeMap.string
|
module.exports.ThangTypeNode = ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.string
|
||||||
valueClass: 'treema-item-thang-type'
|
valueClass: 'treema-thang-type'
|
||||||
@items: null
|
@thangTypesCollection: null # Lives in ThangTypeNode parent class
|
||||||
@itemsCollection: null
|
@thangTypes: null # Lives in ThangTypeNode or subclasses
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super(arguments...)
|
super(arguments...)
|
||||||
@getItems()
|
@getThangTypes()
|
||||||
unless ItemThangTypeNode.itemsCollection.loaded
|
unless ThangTypeNode.thangTypesCollection.loaded
|
||||||
ItemThangTypeNode.itemsCollection.once('sync', @refreshDisplay, @)
|
ThangTypeNode.thangTypesCollection.once('sync', @refreshDisplay, @)
|
||||||
|
|
||||||
buildValueForDisplay: (valEl, data) ->
|
buildValueForDisplay: (valEl, data) ->
|
||||||
@buildValueForDisplaySimply(valEl, @getCurrentItem() or '')
|
@buildValueForDisplaySimply(valEl, @getCurrentThangType() or '')
|
||||||
valEl
|
valEl
|
||||||
|
|
||||||
buildValueForEditing: (valEl, data) ->
|
buildValueForEditing: (valEl, data) ->
|
||||||
super(valEl, data)
|
super(valEl, data)
|
||||||
if ItemThangTypeNode.items
|
input = valEl.find 'input'
|
||||||
source = (item.name for item in ItemThangTypeNode.items when @keyForParent in item.slots)
|
if @constructor.thangTypes
|
||||||
input = valEl.find('input').autocomplete(source: source, minLength: 0, delay: 0, autoFocus: true)
|
source = (thangType.name for thangType in @constructor.thangTypes when @filterThangType thangType)
|
||||||
input.val(@getCurrentItem() or '')
|
input.autocomplete(source: source, minLength: 0, delay: 0, autoFocus: true)
|
||||||
|
input.val(@getCurrentThangType() or '')
|
||||||
valEl
|
valEl
|
||||||
|
|
||||||
getCurrentItem: ->
|
filterThangType: (thangType) -> true
|
||||||
window.itemData = @getData()
|
|
||||||
window.items = ItemThangTypeNode.items
|
getCurrentThangType: ->
|
||||||
return null unless ItemThangTypeNode.items
|
return null unless @constructor.thangTypes
|
||||||
original = @getData()
|
return null unless original = @getData()
|
||||||
return null unless original
|
thangType = _.find @constructor.thangTypes, { original: original }
|
||||||
item = _.find ItemThangTypeNode.items, { original: original }
|
thangType?.name or '...'
|
||||||
item?.name or '...'
|
|
||||||
|
getThangTypes: ->
|
||||||
getItems: ->
|
return if ThangTypeNode.thangTypesCollection
|
||||||
return if ItemThangTypeNode.itemsCollection
|
ThangTypeNode.thangTypesCollection = new CocoCollection([], {
|
||||||
ItemThangTypeNode.itemsCollection = new CocoCollection([], {
|
|
||||||
url: '/db/thang.type'
|
url: '/db/thang.type'
|
||||||
project:['name', 'components', 'original']
|
project:['name', 'components', 'original']
|
||||||
model: ThangType
|
model: ThangType
|
||||||
})
|
})
|
||||||
res = ItemThangTypeNode.itemsCollection.fetch()
|
res = ThangTypeNode.thangTypesCollection.fetch()
|
||||||
ItemThangTypeNode.itemsCollection.once 'sync', => @processItems(ItemThangTypeNode.itemsCollection)
|
ThangTypeNode.thangTypesCollection.once 'sync', => @processThangTypes(ThangTypeNode.thangTypesCollection)
|
||||||
|
|
||||||
processItems: (itemCollection) ->
|
processThangTypes: (thangTypeCollection) ->
|
||||||
ItemThangTypeNode.items = []
|
@constructor.thangTypes = []
|
||||||
for itemThang in itemCollection.models
|
@processThangType thangType for thangType in thangTypeCollection.models
|
||||||
itemComponent = _.find itemThang.get('components'), {original: LevelComponent.ItemID}
|
|
||||||
continue unless itemComponent
|
processThangType: (thangType) ->
|
||||||
slots = itemComponent.config?.slots
|
@constructor.thangTypes.push name: thangType.get('name'), original: thangType.get('original')
|
||||||
continue unless slots?.length
|
|
||||||
ItemThangTypeNode.items.push {
|
|
||||||
name: itemThang.get('name')
|
|
||||||
original: itemThang.get('original')
|
|
||||||
slots: slots
|
|
||||||
}
|
|
||||||
|
|
||||||
saveChanges: ->
|
saveChanges: ->
|
||||||
thangTypeName = @$el.find('input').val()
|
thangTypeName = @$el.find('input').val()
|
||||||
item = _.find(ItemThangTypeNode.items, {name: thangTypeName})
|
thangType = _.find(@constructor.thangTypes, {name: thangTypeName})
|
||||||
return @remove() unless item
|
return @remove() unless thangType
|
||||||
@data = item.original
|
@data = thangType.original
|
||||||
|
|
||||||
|
module.exports.ItemThangTypeNode = ItemThangTypeNode = class ItemThangTypeNode extends ThangTypeNode
|
||||||
|
valueClass: 'treema-item-thang-type'
|
||||||
|
|
||||||
|
filterThangType: (thangType) ->
|
||||||
|
@keyForParent in thangType.slots
|
||||||
|
|
||||||
|
processThangType: (thangType) ->
|
||||||
|
return unless itemComponent = _.find thangType.get('components'), {original: LevelComponent.ItemID}
|
||||||
|
return unless itemComponent.config?.slots?.length
|
||||||
|
@constructor.thangTypes.push name: thangType.get('name'), original: thangType.get('original'), slots: itemComponent.config.slots
|
||||||
|
|
|
@ -75,7 +75,7 @@ module.exports = class AuthModal extends ModalView
|
||||||
userObject.name = @suggestedName if @suggestedName
|
userObject.name = @suggestedName if @suggestedName
|
||||||
for key, val of me.attributes when key in ['preferredLanguage', 'testGroupNumber', 'dateCreated', 'wizardColor1', 'name', 'music', 'volume', 'emails']
|
for key, val of me.attributes when key in ['preferredLanguage', 'testGroupNumber', 'dateCreated', 'wizardColor1', 'name', 'music', 'volume', 'emails']
|
||||||
userObject[key] ?= val
|
userObject[key] ?= val
|
||||||
subscribe = @$el.find('#signup-subscribe').prop('checked')
|
subscribe = @$el.find('#subscribe').prop('checked')
|
||||||
userObject.emails ?= {}
|
userObject.emails ?= {}
|
||||||
userObject.emails.generalNews ?= {}
|
userObject.emails.generalNews ?= {}
|
||||||
userObject.emails.generalNews.enabled = subscribe
|
userObject.emails.generalNews.enabled = subscribe
|
||||||
|
|
|
@ -57,7 +57,7 @@ module.exports = class EmployerSignupModal extends ModalView
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
context = super()
|
context = super()
|
||||||
context.userIsAuthorized = @authorizedWithLinkedIn
|
context.userIsAuthorized = @authorizedWithLinkedIn
|
||||||
context.userHasSignedContract = 'employer' in me.get('permissions')
|
context.userHasSignedContract = 'employer' in me.get('permissions', true)
|
||||||
context.userIsAnonymous = context.me.get('anonymous')
|
context.userIsAnonymous = context.me.get('anonymous')
|
||||||
context.sentMoreInfoEmail = @sentMoreInfoEmail
|
context.sentMoreInfoEmail = @sentMoreInfoEmail
|
||||||
context
|
context
|
||||||
|
|
|
@ -159,5 +159,5 @@ module.exports = class Spell
|
||||||
return true if @spectateView # Use transpiled code for both teams if we're just spectating.
|
return true if @spectateView # Use transpiled code for both teams if we're just spectating.
|
||||||
return true if @isEnemySpell() # Use transpiled for enemy spells.
|
return true if @isEnemySpell() # Use transpiled for enemy spells.
|
||||||
# Players without permissions can't view the raw code.
|
# Players without permissions can't view the raw code.
|
||||||
return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions'))
|
return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions', true))
|
||||||
false
|
false
|
||||||
|
|
|
@ -72,7 +72,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
finishInit: ->
|
finishInit: ->
|
||||||
return unless @userID
|
return unless @userID
|
||||||
@uploadFilePath = "db/user/#{@userID}"
|
@uploadFilePath = "db/user/#{@userID}"
|
||||||
|
|
||||||
if @user?.get('firstName')
|
if @user?.get('firstName')
|
||||||
jobProfile = @user.get('jobProfile')
|
jobProfile = @user.get('jobProfile')
|
||||||
jobProfile ?= {}
|
jobProfile ?= {}
|
||||||
|
@ -81,7 +81,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
@user.set('jobProfile', jobProfile)
|
@user.set('jobProfile', jobProfile)
|
||||||
|
|
||||||
@highlightedContainers = []
|
@highlightedContainers = []
|
||||||
if me.isAdmin() or 'employer' in me.get('permissions')
|
if me.isAdmin() or 'employer' in me.get('permissions', true)
|
||||||
$.post "/db/user/#{me.id}/track/view_candidate"
|
$.post "/db/user/#{me.id}/track/view_candidate"
|
||||||
$.post "/db/user/#{@userID}/track/viewed_by_employer" unless me.isAdmin()
|
$.post "/db/user/#{@userID}/track/viewed_by_employer" unless me.isAdmin()
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'candidate_sessions').model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'candidate_sessions').model
|
||||||
|
@ -235,7 +235,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
context.rawProfile = @user.get('jobProfile') or {}
|
context.rawProfile = @user.get('jobProfile') or {}
|
||||||
context.user = @user
|
context.user = @user
|
||||||
context.myProfile = @isMe()
|
context.myProfile = @isMe()
|
||||||
context.allowedToViewJobProfile = @user and (me.isAdmin() or 'employer' in me.get('permissions') or (context.myProfile && !me.get('anonymous')))
|
context.allowedToViewJobProfile = @user and (me.isAdmin() or 'employer' in me.get('permissions', true) or (context.myProfile && !me.get('anonymous')))
|
||||||
context.allowedToEditJobProfile = @user and (me.isAdmin() or (context.myProfile && !me.get('anonymous')))
|
context.allowedToEditJobProfile = @user and (me.isAdmin() or (context.myProfile && !me.get('anonymous')))
|
||||||
context.profileApproved = @user?.get 'jobProfileApproved'
|
context.profileApproved = @user?.get 'jobProfileApproved'
|
||||||
context.progress = @progress ? @updateProgress()
|
context.progress = @progress ? @updateProgress()
|
||||||
|
@ -589,4 +589,4 @@ module.exports = class JobProfileView extends UserView
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@remarkTreema?.destroy()
|
@remarkTreema?.destroy()
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -224,7 +224,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
res.end()
|
res.end()
|
||||||
|
|
||||||
getLevelSessionsForEmployer: (req, res, userID) ->
|
getLevelSessionsForEmployer: (req, res, userID) ->
|
||||||
return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in (req.user.get('permissions') ? []))
|
||||||
query = creator: userID, levelID: {$in: ['gridmancer', 'greed', 'dungeon-arena', 'brawlwood', 'gold-rush']}
|
query = creator: userID, levelID: {$in: ['gridmancer', 'greed', 'dungeon-arena', 'brawlwood', 'gold-rush']}
|
||||||
projection = 'levelName levelID team playtime codeLanguage submitted code totalScore teamSpells level'
|
projection = 'levelName levelID team playtime codeLanguage submitted code totalScore teamSpells level'
|
||||||
LevelSession.find(query).select(projection).exec (err, documents) =>
|
LevelSession.find(query).select(projection).exec (err, documents) =>
|
||||||
|
@ -280,7 +280,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
return @sendMethodNotAllowed res unless req.method is 'POST'
|
return @sendMethodNotAllowed res unless req.method is 'POST'
|
||||||
isMe = userID is req.user._id + ''
|
isMe = userID is req.user._id + ''
|
||||||
isAuthorized = isMe or req.user.isAdmin()
|
isAuthorized = isMe or req.user.isAdmin()
|
||||||
isAuthorized ||= ('employer' in req.user.get('permissions')) and (activityName in ['viewed_by_employer', 'contacted_by_employer'])
|
isAuthorized ||= ('employer' in (req.user.get('permissions') ? [])) and (activityName in ['viewed_by_employer', 'contacted_by_employer'])
|
||||||
return @sendUnauthorizedError res unless isAuthorized
|
return @sendUnauthorizedError res unless isAuthorized
|
||||||
updateUser = (user) =>
|
updateUser = (user) =>
|
||||||
activity = user.trackActivity activityName, increment
|
activity = user.trackActivity activityName, increment
|
||||||
|
@ -303,7 +303,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
if not profileData.id or not profileData.positions or not profileData.emailAddress or not profileData.firstName or not profileData.lastName
|
if not profileData.id or not profileData.positions or not profileData.emailAddress or not profileData.firstName or not profileData.lastName
|
||||||
return errors.badInput(res, 'You need to have a more complete profile to sign up for this service.')
|
return errors.badInput(res, 'You need to have a more complete profile to sign up for this service.')
|
||||||
@modelClass.findById(req.user.id).exec (err, user) =>
|
@modelClass.findById(req.user.id).exec (err, user) =>
|
||||||
if user.get('employerAt') or user.get('signedEmployerAgreement') or 'employer' in user.get('permissions')
|
if user.get('employerAt') or user.get('signedEmployerAgreement') or 'employer' in (user.get('permissions') ? [])
|
||||||
return errors.conflict(res, 'You already have signed the agreement!')
|
return errors.conflict(res, 'You already have signed the agreement!')
|
||||||
#TODO: Search for the current position
|
#TODO: Search for the current position
|
||||||
employerAt = _.filter(profileData.positions.values, 'isCurrent')[0]?.company.name ? 'Not available'
|
employerAt = _.filter(profileData.positions.values, 'isCurrent')[0]?.company.name ? 'Not available'
|
||||||
|
@ -322,7 +322,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
res.end()
|
res.end()
|
||||||
|
|
||||||
getCandidates: (req, res) ->
|
getCandidates: (req, res) ->
|
||||||
authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
authorized = req.user.isAdmin() or ('employer' in (req.user.get('permissions') ? []))
|
||||||
months = if req.user.isAdmin() then 12 else 2
|
months = if req.user.isAdmin() then 12 else 2
|
||||||
since = (new Date((new Date()) - months * 30.4 * 86400 * 1000)).toISOString()
|
since = (new Date((new Date()) - months * 30.4 * 86400 * 1000)).toISOString()
|
||||||
query = {'jobProfile.updated': {$gt: since}}
|
query = {'jobProfile.updated': {$gt: since}}
|
||||||
|
|
Reference in a new issue