First round of getting the site to use the new defaults system, in particular the job profile view.
This commit is contained in:
parent
fe2faefa5d
commit
1c5db3f2b7
21 changed files with 129 additions and 151 deletions
|
@ -11,6 +11,7 @@ module.exports = class Achievement extends CocoModel
|
||||||
|
|
||||||
# TODO logic is duplicated in Mongoose Achievement schema
|
# TODO logic is duplicated in Mongoose Achievement schema
|
||||||
getExpFunction: ->
|
getExpFunction: ->
|
||||||
|
# TODO DEFAULTS
|
||||||
kind = @get('function')?.kind or jsonschema.properties.function.default.kind
|
kind = @get('function')?.kind or jsonschema.properties.function.default.kind
|
||||||
parameters = @get('function')?.parameters or jsonschema.properties.function.default.parameters
|
parameters = @get('function')?.parameters or jsonschema.properties.function.default.parameters
|
||||||
return utils.functionCreators[kind](parameters) if kind of utils.functionCreators
|
return utils.functionCreators[kind](parameters) if kind of utils.functionCreators
|
||||||
|
|
|
@ -9,15 +9,12 @@ class CocoModel extends Backbone.Model
|
||||||
notyErrors: true
|
notyErrors: true
|
||||||
@schema: null
|
@schema: null
|
||||||
|
|
||||||
getMe: -> @me or @me = require('lib/auth').me
|
|
||||||
|
|
||||||
initialize: (attributes, options) ->
|
initialize: (attributes, options) ->
|
||||||
super(arguments...)
|
super(arguments...)
|
||||||
options ?= {}
|
options ?= {}
|
||||||
@setProjection options.project
|
@setProjection options.project
|
||||||
if not @constructor.className
|
if not @constructor.className
|
||||||
console.error("#{@} needs a className set.")
|
console.error("#{@} needs a className set.")
|
||||||
@addSchemaDefaults()
|
|
||||||
@on 'sync', @onLoaded, @
|
@on 'sync', @onLoaded, @
|
||||||
@on 'error', @onError, @
|
@on 'error', @onError, @
|
||||||
@on 'add', @onLoaded, @
|
@on 'add', @onLoaded, @
|
||||||
|
@ -45,14 +42,31 @@ class CocoModel extends Backbone.Model
|
||||||
@loadFromBackup()
|
@loadFromBackup()
|
||||||
|
|
||||||
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
||||||
|
|
||||||
|
attributesWithDefaults: undefined
|
||||||
|
|
||||||
|
get: (attribute, withDefault=false) ->
|
||||||
|
if withDefault
|
||||||
|
if @attributesWithDefaults is undefined then @buildAttributesWithDefaults()
|
||||||
|
return @attributesWithDefaults[attribute]
|
||||||
|
else
|
||||||
|
super(attribute)
|
||||||
|
|
||||||
set: ->
|
set: ->
|
||||||
|
delete @attributesWithDefaults
|
||||||
inFlux = @loading or not @loaded
|
inFlux = @loading or not @loaded
|
||||||
@markToRevert() unless inFlux or @_revertAttributes
|
@markToRevert() unless inFlux or @_revertAttributes
|
||||||
res = super(arguments...)
|
res = super(arguments...)
|
||||||
@saveBackup() if @saveBackups and (not inFlux) and @hasLocalChanges()
|
@saveBackup() if @saveBackups and (not inFlux) and @hasLocalChanges()
|
||||||
res
|
res
|
||||||
|
|
||||||
|
buildAttributesWithDefaults: ->
|
||||||
|
t0 = new Date()
|
||||||
|
clone = $.extend true, {}, @attributes
|
||||||
|
TreemaNode.utils.populateDefaults(clone, @schema())
|
||||||
|
@attributesWithDefaults = clone
|
||||||
|
console.debug "Populated defaults for #{@attributes.name or @type()} in #{new Date() - t0}ms"
|
||||||
|
|
||||||
loadFromBackup: ->
|
loadFromBackup: ->
|
||||||
return unless @saveBackups
|
return unless @saveBackups
|
||||||
existing = storage.load @id
|
existing = storage.load @id
|
||||||
|
@ -161,28 +175,12 @@ class CocoModel extends Backbone.Model
|
||||||
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') or []).concat({access: 'read', target: 'public'})
|
||||||
|
|
||||||
addSchemaDefaults: ->
|
|
||||||
return if @addedSchemaDefaults
|
|
||||||
@addedSchemaDefaults = true
|
|
||||||
for prop, defaultValue of @constructor.schema.default or {}
|
|
||||||
continue if @get(prop)?
|
|
||||||
#console.log 'setting', prop, 'to', defaultValue, 'from attributes.default'
|
|
||||||
@set prop, defaultValue
|
|
||||||
for prop, sch of @constructor.schema.properties or {}
|
|
||||||
continue if @get(prop)?
|
|
||||||
continue if prop is 'emails' # hack, defaults are handled through User.coffee's email-specific methods.
|
|
||||||
#console.log 'setting', prop, 'to', sch.default, 'from sch.default' if sch.default?
|
|
||||||
@set prop, sch.default if sch.default?
|
|
||||||
if @loaded
|
|
||||||
@loadFromBackup()
|
|
||||||
|
|
||||||
@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
|
||||||
|
|
||||||
hasReadAccess: (actor) ->
|
hasReadAccess: (actor) ->
|
||||||
# actor is a User object
|
# actor is a User object
|
||||||
|
actor ?= me
|
||||||
actor ?= @getMe()
|
|
||||||
return true if actor.isAdmin()
|
return true if actor.isAdmin()
|
||||||
if @get('permissions')?
|
if @get('permissions')?
|
||||||
for permission in @get('permissions')
|
for permission in @get('permissions')
|
||||||
|
@ -193,8 +191,7 @@ class CocoModel extends Backbone.Model
|
||||||
|
|
||||||
hasWriteAccess: (actor) ->
|
hasWriteAccess: (actor) ->
|
||||||
# actor is a User object
|
# actor is a User object
|
||||||
|
actor ?= me
|
||||||
actor ?= @getMe()
|
|
||||||
return true if actor.isAdmin()
|
return true if actor.isAdmin()
|
||||||
if @get('permissions')?
|
if @get('permissions')?
|
||||||
for permission in @get('permissions')
|
for permission in @get('permissions')
|
||||||
|
|
|
@ -135,6 +135,7 @@ module.exports = class Level extends CocoModel
|
||||||
visit comp
|
visit comp
|
||||||
thang.components = sorted
|
thang.components = sorted
|
||||||
|
|
||||||
|
# TODO DEFAULTS
|
||||||
fillInDefaultComponentConfiguration: (thangs, levelComponents) ->
|
fillInDefaultComponentConfiguration: (thangs, levelComponents) ->
|
||||||
for thang in thangs
|
for thang in thangs
|
||||||
for component in thang.components or []
|
for component in thang.components or []
|
||||||
|
|
|
@ -9,13 +9,6 @@ module.exports = class User extends CocoModel
|
||||||
urlRoot: '/db/user'
|
urlRoot: '/db/user'
|
||||||
notyErrors: false
|
notyErrors: false
|
||||||
|
|
||||||
defaults:
|
|
||||||
points: 0
|
|
||||||
|
|
||||||
initialize: ->
|
|
||||||
super()
|
|
||||||
@migrateEmails()
|
|
||||||
|
|
||||||
onLoaded: ->
|
onLoaded: ->
|
||||||
CocoModel.pollAchievements() # Check for achievements on login
|
CocoModel.pollAchievements() # Check for achievements on login
|
||||||
super arguments...
|
super arguments...
|
||||||
|
@ -24,14 +17,9 @@ module.exports = class User extends CocoModel
|
||||||
permissions = @attributes['permissions'] or []
|
permissions = @attributes['permissions'] or []
|
||||||
return 'admin' in permissions
|
return 'admin' in permissions
|
||||||
|
|
||||||
isAnonymous: ->
|
isAnonymous: -> @get('anonymous', true)
|
||||||
@get 'anonymous'
|
displayName: -> @get('name', true)
|
||||||
|
lang: -> @get('preferredLanguage', true)
|
||||||
displayName: ->
|
|
||||||
@get('name') or 'Anoner'
|
|
||||||
|
|
||||||
lang: ->
|
|
||||||
@get('preferredLanguage') or 'en-US'
|
|
||||||
|
|
||||||
getPhotoURL: (size=80, useJobProfilePhoto=false, useEmployerPageAvatar=false) ->
|
getPhotoURL: (size=80, useJobProfilePhoto=false, useEmployerPageAvatar=false) ->
|
||||||
photoURL = if useJobProfilePhoto then @get('jobProfile')?.photoURL else null
|
photoURL = if useJobProfilePhoto then @get('jobProfile')?.photoURL else null
|
||||||
|
@ -57,33 +45,13 @@ module.exports = class User extends CocoModel
|
||||||
done response.name
|
done response.name
|
||||||
|
|
||||||
getEnabledEmails: ->
|
getEnabledEmails: ->
|
||||||
@migrateEmails()
|
(emailName for emailName, emailDoc of @get('emails', true) when emailDoc.enabled)
|
||||||
emails = _.clone(@get('emails')) or {}
|
|
||||||
emails = _.defaults emails, @schema().properties.emails.default
|
|
||||||
(emailName for emailName, emailDoc of emails when emailDoc.enabled)
|
|
||||||
|
|
||||||
setEmailSubscription: (name, enabled) ->
|
setEmailSubscription: (name, enabled) ->
|
||||||
newSubs = _.clone(@get('emails')) or {}
|
newSubs = _.clone(@get('emails')) or {}
|
||||||
(newSubs[name] ?= {}).enabled = enabled
|
(newSubs[name] ?= {}).enabled = enabled
|
||||||
@set 'emails', newSubs
|
@set 'emails', newSubs
|
||||||
|
|
||||||
emailMap:
|
|
||||||
announcement: 'generalNews'
|
|
||||||
developer: 'archmageNews'
|
|
||||||
tester: 'adventurerNews'
|
|
||||||
level_creator: 'artisanNews'
|
|
||||||
article_editor: 'scribeNews'
|
|
||||||
translator: 'diplomatNews'
|
|
||||||
support: 'ambassadorNews'
|
|
||||||
notification: 'anyNotes'
|
|
||||||
|
|
||||||
migrateEmails: ->
|
|
||||||
return if @attributes.emails or not @attributes.emailSubscriptions
|
|
||||||
oldSubs = @get('emailSubscriptions') or []
|
|
||||||
newSubs = {}
|
|
||||||
newSubs[newSubName] = {enabled: oldSubName in oldSubs} for oldSubName, newSubName of @emailMap
|
|
||||||
@set('emails', newSubs)
|
|
||||||
|
|
||||||
isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled
|
isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled
|
||||||
|
|
||||||
a = 5
|
a = 5
|
||||||
|
|
|
@ -3,6 +3,20 @@ emailSubscriptions = ['announcement', 'tester', 'level_creator', 'developer', 'a
|
||||||
|
|
||||||
UserSchema = c.object
|
UserSchema = c.object
|
||||||
title: 'User'
|
title: 'User'
|
||||||
|
default:
|
||||||
|
visa: 'Authorized to work in the US'
|
||||||
|
music: true
|
||||||
|
name: 'Anoner'
|
||||||
|
autocastDelay: 5000
|
||||||
|
emails: {}
|
||||||
|
permissions: []
|
||||||
|
anonymous: true
|
||||||
|
points: 0
|
||||||
|
preferredLanguage: 'en-US'
|
||||||
|
aceConfig: {}
|
||||||
|
simulatedBy: 0
|
||||||
|
simulatedFor: 0
|
||||||
|
jobProfile: {}
|
||||||
|
|
||||||
c.extendNamedProperties UserSchema # let's have the name be the first property
|
c.extendNamedProperties UserSchema # let's have the name be the first property
|
||||||
|
|
||||||
|
@ -31,7 +45,6 @@ visa = c.shortString
|
||||||
title: 'US Work Status'
|
title: 'US Work Status'
|
||||||
description: 'Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)'
|
description: 'Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)'
|
||||||
enum: ['Authorized to work in the US', 'Need visa sponsorship']
|
enum: ['Authorized to work in the US', 'Need visa sponsorship']
|
||||||
default: 'Authorized to work in the US'
|
|
||||||
|
|
||||||
_.extend UserSchema.properties,
|
_.extend UserSchema.properties,
|
||||||
email: c.shortString({title: 'Email', format: 'email'})
|
email: c.shortString({title: 'Email', format: 'email'})
|
||||||
|
@ -47,12 +60,12 @@ _.extend UserSchema.properties,
|
||||||
|
|
||||||
wizardColor1: c.pct({title: 'Wizard Clothes Color'})
|
wizardColor1: c.pct({title: 'Wizard Clothes Color'})
|
||||||
volume: c.pct({title: 'Volume'})
|
volume: c.pct({title: 'Volume'})
|
||||||
music: {type: 'boolean', default: true}
|
music: { type: 'boolean' }
|
||||||
autocastDelay: {type: 'integer', 'default': 5000}
|
autocastDelay: { type: 'integer' }
|
||||||
lastLevel: {type: 'string'}
|
lastLevel: { type: 'string' }
|
||||||
|
|
||||||
emailSubscriptions: c.array {uniqueItems: true}, {'enum': emailSubscriptions}
|
emailSubscriptions: c.array {uniqueItems: true}, {'enum': emailSubscriptions}
|
||||||
emails: c.object {title: 'Email Settings', default: {generalNews: {enabled: true}, anyNotes: {enabled: true}, recruitNotes: {enabled: true}}},
|
emails: c.object {title: 'Email Settings', default: generalNews: {enabled: true}, anyNotes: {enabled: true}, recruitNotes: {enabled: true} },
|
||||||
# newsletters
|
# newsletters
|
||||||
generalNews: {$ref: '#/definitions/emailSubscription'}
|
generalNews: {$ref: '#/definitions/emailSubscription'}
|
||||||
adventurerNews: {$ref: '#/definitions/emailSubscription'}
|
adventurerNews: {$ref: '#/definitions/emailSubscription'}
|
||||||
|
@ -68,9 +81,9 @@ _.extend UserSchema.properties,
|
||||||
employerNotes: {$ref: '#/definitions/emailSubscription'}
|
employerNotes: {$ref: '#/definitions/emailSubscription'}
|
||||||
|
|
||||||
# server controlled
|
# server controlled
|
||||||
permissions: c.array {'default': []}, c.shortString()
|
permissions: c.array {}, c.shortString()
|
||||||
dateCreated: c.date({title: 'Date Joined'})
|
dateCreated: c.date({title: 'Date Joined'})
|
||||||
anonymous: {type: 'boolean', 'default': true}
|
anonymous: {type: 'boolean' }
|
||||||
testGroupNumber: {type: 'integer', minimum: 0, maximum: 256, exclusiveMaximum: true}
|
testGroupNumber: {type: 'integer', minimum: 0, maximum: 256, exclusiveMaximum: true}
|
||||||
mailChimp: {type: 'object'}
|
mailChimp: {type: 'object'}
|
||||||
hourOfCode: {type: 'boolean'}
|
hourOfCode: {type: 'boolean'}
|
||||||
|
@ -84,36 +97,36 @@ _.extend UserSchema.properties,
|
||||||
emailHash: {type: 'string'}
|
emailHash: {type: 'string'}
|
||||||
|
|
||||||
#Internationalization stuff
|
#Internationalization stuff
|
||||||
preferredLanguage: {type: 'string', default: 'en', 'enum': c.getLanguageCodeArray()}
|
preferredLanguage: {type: 'string', 'enum': c.getLanguageCodeArray()}
|
||||||
|
|
||||||
signedCLA: c.date({title: 'Date Signed the CLA'})
|
signedCLA: c.date({title: 'Date Signed the CLA'})
|
||||||
wizard: c.object {},
|
wizard: c.object {},
|
||||||
colorConfig: c.object {additionalProperties: c.colorConfig()}
|
colorConfig: c.object {additionalProperties: c.colorConfig()}
|
||||||
|
|
||||||
aceConfig: c.object {},
|
aceConfig: c.object { default: { language: 'javascript', keyBindings: 'default', invisibles: false, indentGuides: false, behaviors: false, liveCompletion: true }},
|
||||||
language: {type: 'string', 'default': 'javascript', 'enum': ['javascript', 'coffeescript', 'python', 'clojure', 'lua', 'io']}
|
language: {type: 'string', 'enum': ['javascript', 'coffeescript', 'python', 'clojure', 'lua', 'io']}
|
||||||
keyBindings: {type: 'string', 'default': 'default', 'enum': ['default', 'vim', 'emacs']}
|
keyBindings: {type: 'string', 'enum': ['default', 'vim', 'emacs']}
|
||||||
invisibles: {type: 'boolean', 'default': false}
|
invisibles: {type: 'boolean' }
|
||||||
indentGuides: {type: 'boolean', 'default': false}
|
indentGuides: {type: 'boolean' }
|
||||||
behaviors: {type: 'boolean', 'default': false}
|
behaviors: {type: 'boolean' }
|
||||||
liveCompletion: {type: 'boolean', 'default': true}
|
liveCompletion: {type: 'boolean' }
|
||||||
|
|
||||||
simulatedBy: {type: 'integer', minimum: 0, default: 0}
|
simulatedBy: {type: 'integer', minimum: 0 }
|
||||||
simulatedFor: {type: 'integer', minimum: 0, default: 0}
|
simulatedFor: {type: 'integer', minimum: 0 }
|
||||||
|
|
||||||
jobProfile: c.object {title: 'Job Profile', required: ['lookingFor', 'jobTitle', 'active', 'name', 'city', 'country', 'skills', 'experience', 'shortDescription', 'longDescription', 'visa', 'work', 'education', 'projects', 'links']},
|
jobProfile: c.object {title: 'Job Profile', default: { active: false, lookingFor: 'Full-time', jobTitle: 'Software Developer', city: 'Defaultsville, CA', country: 'USA', skills: ['javascript'], shortDescription: 'Programmer seeking to build great software.', longDescription: '* I write great code.\n* You need great code?\n* Great!' }},
|
||||||
lookingFor: {title: 'Looking For', type: 'string', enum: ['Full-time', 'Part-time', 'Remote', 'Contracting', 'Internship'], default: 'Full-time', description: 'What kind of developer position do you want?'}
|
lookingFor: {title: 'Looking For', type: 'string', enum: ['Full-time', 'Part-time', 'Remote', 'Contracting', 'Internship'], description: 'What kind of developer position do you want?'}
|
||||||
jobTitle: {type: 'string', maxLength: 50, title: 'Desired Job Title', description: 'What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer"', default: 'Software Developer'}
|
jobTitle: {type: 'string', maxLength: 50, title: 'Desired Job Title', description: 'What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer"' }
|
||||||
active: {title: 'Open to Offers', type: 'boolean', description: 'Want interview offers right now?'}
|
active: {title: 'Open to Offers', type: 'boolean', description: 'Want interview offers right now?'}
|
||||||
updated: c.date {title: 'Last Updated', description: 'How fresh your profile appears to employers. Profiles go inactive after 4 weeks.'}
|
updated: c.date {title: 'Last Updated', description: 'How fresh your profile appears to employers. Profiles go inactive after 4 weeks.'}
|
||||||
name: c.shortString {title: 'Name', description: 'Name you want employers to see, like "Nick Winter".'}
|
name: c.shortString {title: 'Name', description: 'Name you want employers to see, like "Nick Winter".'}
|
||||||
city: c.shortString {title: 'City', description: 'City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX".', default: 'Defaultsville, CA', format: 'city'}
|
city: c.shortString {title: 'City', description: 'City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX".', format: 'city'}
|
||||||
country: c.shortString {title: 'Country', description: 'Country you want to work in (or live in now), like "USA" or "France".', default: 'USA', format: 'country'}
|
country: c.shortString {title: 'Country', description: 'Country you want to work in (or live in now), like "USA" or "France".', format: 'country'}
|
||||||
skills: c.array {title: 'Skills', description: 'Tag relevant developer skills in order of proficiency.', default: ['javascript'], minItems: 1, maxItems: 30, uniqueItems: true},
|
skills: c.array {title: 'Skills', description: 'Tag relevant developer skills in order of proficiency', maxItems: 30, uniqueItems: true},
|
||||||
{type: 'string', minLength: 1, maxLength: 50, description: 'Ex.: "objective-c", "mongodb", "rails", "android", "javascript"', format: 'skill'}
|
{type: 'string', minLength: 1, maxLength: 50, description: 'Ex.: "objective-c", "mongodb", "rails", "android", "javascript"', format: 'skill'}
|
||||||
experience: {type: 'integer', title: 'Years of Experience', minimum: 0, description: 'How many years of professional experience (getting paid) developing software do you have?'}
|
experience: {type: 'integer', title: 'Years of Experience', minimum: 0, description: 'How many years of professional experience (getting paid) developing software do you have?'}
|
||||||
shortDescription: {type: 'string', maxLength: 140, title: 'Short Description', description: 'Who are you, and what are you looking for? 140 characters max.', default: 'Programmer seeking to build great software.'}
|
shortDescription: {type: 'string', maxLength: 140, title: 'Short Description', description: 'Who are you, and what are you looking for? 140 characters max.' }
|
||||||
longDescription: {type: 'string', maxLength: 600, title: 'Description', description: 'Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max.', format: 'markdown', default: '* I write great code.\n* You need great code?\n* Great!'}
|
longDescription: {type: 'string', maxLength: 600, title: 'Description', description: 'Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max.', format: 'markdown' }
|
||||||
visa: visa
|
visa: visa
|
||||||
work: c.array {title: 'Work Experience', description: 'List your relevant work experience, most recent first.'},
|
work: c.array {title: 'Work Experience', description: 'List your relevant work experience, most recent first.'},
|
||||||
c.object {title: 'Job', description: 'Some work experience you had.', required: ['employer', 'role', 'duration']},
|
c.object {title: 'Job', description: 'Some work experience you had.', required: ['employer', 'role', 'duration']},
|
||||||
|
@ -129,14 +142,14 @@ _.extend UserSchema.properties,
|
||||||
description: {type: 'string', title: 'Description', description: 'Highlight anything about this educational experience. (140 chars; optional)', maxLength: 140}
|
description: {type: 'string', title: 'Description', description: 'Highlight anything about this educational experience. (140 chars; optional)', maxLength: 140}
|
||||||
projects: c.array {title: 'Projects (Top 3)', description: 'Highlight your projects to amaze employers.', maxItems: 3},
|
projects: c.array {title: 'Projects (Top 3)', description: 'Highlight your projects to amaze employers.', maxItems: 3},
|
||||||
c.object {title: 'Project', description: 'A project you created.', required: ['name', 'description', 'picture'], default: {name: 'My Project', description: 'A project I worked on.', link: 'http://example.com', picture: ''}},
|
c.object {title: 'Project', description: 'A project you created.', required: ['name', 'description', 'picture'], default: {name: 'My Project', description: 'A project I worked on.', link: 'http://example.com', picture: ''}},
|
||||||
name: c.shortString {title: 'Project Name', description: 'What was the project called?', default: 'My Project'}
|
name: c.shortString {title: 'Project Name', description: 'What was the project called?' }
|
||||||
description: {type: 'string', title: 'Description', description: 'Briefly describe the project.', maxLength: 400, default: 'A project I worked on.', format: 'markdown'}
|
description: {type: 'string', title: 'Description', description: 'Briefly describe the project.', maxLength: 400, format: 'markdown'}
|
||||||
picture: {type: 'string', title: 'Picture', format: 'image-file', description: 'Upload a 230x115px or larger image showing off the project.'}
|
picture: {type: 'string', title: 'Picture', format: 'image-file', description: 'Upload a 230x115px or larger image showing off the project.'}
|
||||||
link: c.url {title: 'Link', description: 'Link to the project.', default: 'http://example.com'}
|
link: c.url {title: 'Link', description: 'Link to the project.'}
|
||||||
links: c.array {title: 'Personal and Social Links', description: 'Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog.'},
|
links: c.array {title: 'Personal and Social Links', description: 'Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog.'},
|
||||||
c.object {title: 'Link', description: 'A link to another site you want to highlight, like your GitHub, your LinkedIn, or your blog.', required: ['name', 'link']},
|
c.object {title: 'Link', description: 'A link to another site you want to highlight, like your GitHub, your LinkedIn, or your blog.', required: ['name', 'link'], default: {link: 'http://example.com'}},
|
||||||
name: {type: 'string', maxLength: 30, title: 'Link Name', description: 'What are you linking to? Ex: "Personal Website", "GitHub"', format: 'link-name'}
|
name: {type: 'string', maxLength: 30, title: 'Link Name', description: 'What are you linking to? Ex: "Personal Website", "GitHub"', format: 'link-name'}
|
||||||
link: c.url {title: 'Link', description: 'The URL.', default: 'http://example.com'}
|
link: c.url {title: 'Link', description: 'The URL.' }
|
||||||
photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image if you want to show a different profile picture to employers than your normal avatar.'}
|
photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image if you want to show a different profile picture to employers than your normal avatar.'}
|
||||||
curated: c.object {title: 'Curated', required: ['shortDescription', 'mainTag', 'location', 'education', 'workHistory', 'phoneScreenFilter', 'schoolFilter', 'locationFilter', 'roleFilter', 'seniorityFilter']},
|
curated: c.object {title: 'Curated', required: ['shortDescription', 'mainTag', 'location', 'education', 'workHistory', 'phoneScreenFilter', 'schoolFilter', 'locationFilter', 'roleFilter', 'seniorityFilter']},
|
||||||
shortDescription:
|
shortDescription:
|
||||||
|
@ -169,7 +182,7 @@ _.extend UserSchema.properties,
|
||||||
description: 'Should this candidate be prominently featured on the site?'
|
description: 'Should this candidate be prominently featured on the site?'
|
||||||
jobProfileApproved: {title: 'Job Profile Approved', type: 'boolean', description: 'Whether your profile has been approved by CodeCombat.'}
|
jobProfileApproved: {title: 'Job Profile Approved', type: 'boolean', description: 'Whether your profile has been approved by CodeCombat.'}
|
||||||
jobProfileApprovedDate: c.date {title: 'Approved date', description: 'The date that the candidate was approved'}
|
jobProfileApprovedDate: c.date {title: 'Approved date', description: 'The date that the candidate was approved'}
|
||||||
jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: 'CodeCombat\'s notes on the candidate.', format: 'markdown', default: ''}
|
jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: 'CodeCombat\'s notes on the candidate.', format: 'markdown' }
|
||||||
employerAt: c.shortString {description: 'If given employer permissions to view job candidates, for which employer?'}
|
employerAt: c.shortString {description: 'If given employer permissions to view job candidates, for which employer?'}
|
||||||
signedEmployerAgreement: c.object {},
|
signedEmployerAgreement: c.object {},
|
||||||
linkedinID: c.shortString {title: 'LinkedInID', description: 'The user\'s LinkedIn ID when they signed the contract.'}
|
linkedinID: c.shortString {title: 'LinkedInID', description: 'The user\'s LinkedIn ID when they signed the contract.'}
|
||||||
|
@ -252,10 +265,11 @@ _.extend UserSchema.properties,
|
||||||
|
|
||||||
c.extendBasicProperties UserSchema, 'user'
|
c.extendBasicProperties UserSchema, 'user'
|
||||||
|
|
||||||
c.definitions =
|
UserSchema.definitions =
|
||||||
emailSubscription =
|
emailSubscription: c.object { default: { enabled: true, count: 0 } }, {
|
||||||
enabled: {type: 'boolean'}
|
enabled: {type: 'boolean'}
|
||||||
lastSent: c.date()
|
lastSent: c.date()
|
||||||
count: {type: 'integer'}
|
count: {type: 'integer'}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = UserSchema
|
module.exports = UserSchema
|
||||||
|
|
|
@ -117,7 +117,7 @@ block content
|
||||||
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
|
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
|
||||||
|
|
||||||
.editable-section#basic-info-container
|
.editable-section#basic-info-container
|
||||||
- var editableDefaults = editing && profile.city == jobProfileSchema.properties.city.default
|
- var editableDefaults = editing && !rawProfile.city
|
||||||
div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info")
|
div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info")
|
||||||
.editable-icon.glyphicon.glyphicon-pencil
|
.editable-icon.glyphicon.glyphicon-pencil
|
||||||
if editableDefaults
|
if editableDefaults
|
||||||
|
@ -224,7 +224,7 @@ block content
|
||||||
#short-description-container.editable-section
|
#short-description-container.editable-section
|
||||||
.editable-display(title="Click to write your tagline")
|
.editable-display(title="Click to write your tagline")
|
||||||
.editable-icon.glyphicon.glyphicon-pencil
|
.editable-icon.glyphicon.glyphicon-pencil
|
||||||
if editing && (!profile.shortDescription || profile.shortDescription == jobProfileSchema.properties.shortDescription.default)
|
if editing && !rawProfile.shortDescription
|
||||||
h3.edit-label(data-i18n="account_profile.short_description_header") Write a short description of yourself
|
h3.edit-label(data-i18n="account_profile.short_description_header") Write a short description of yourself
|
||||||
p.edit-example-text(data-i18n="account_profile.short_description_blurb") Add a tagline to help an employer quickly learn more about you.
|
p.edit-example-text(data-i18n="account_profile.short_description_blurb") Add a tagline to help an employer quickly learn more about you.
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ block content
|
||||||
#long-description-container.editable-section
|
#long-description-container.editable-section
|
||||||
.editable-display(title="Click to start writing your longer description")
|
.editable-display(title="Click to start writing your longer description")
|
||||||
.editable-icon.glyphicon.glyphicon-pencil
|
.editable-icon.glyphicon.glyphicon-pencil
|
||||||
- var modified = profile.longDescription && profile.longDescription != jobProfileSchema.properties.longDescription.default
|
- var modified = rawProfile.longDescription
|
||||||
if editing && !modified
|
if editing && !modified
|
||||||
h3.edit-label(data-i18n="account_profile.long_description_header") Describe your desired position
|
h3.edit-label(data-i18n="account_profile.long_description_header") Describe your desired position
|
||||||
p.edit-example-text(data-i18n="account_profile.long_description_blurb") Tell employers how awesome you are and what role you want.
|
p.edit-example-text(data-i18n="account_profile.long_description_blurb") Tell employers how awesome you are and what role you want.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
.editable-icon.glyphicon.glyphicon-pencil
|
.editable-icon.glyphicon.glyphicon-pencil
|
||||||
img.profile-photo(src=me.getPhotoURL(230))
|
img.profile-photo(src=me.getPhotoURL(230))
|
||||||
.form-group
|
.form-group
|
||||||
input#player-name.profile-caption(name="playerName", type="text", value=me.get('name') || 'Anoner')
|
input#player-name.profile-caption(name="playerName", type="text", value=me.get('name', true))
|
||||||
|
|
||||||
.form
|
.form
|
||||||
h3(data-i18n="options.general_options") General Options
|
h3(data-i18n="options.general_options") General Options
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
strong.tip.rare(data-i18n='play_level.tip_first_language') The most disastrous thing that you can ever learn is your first programming language. - Alan Kay
|
strong.tip.rare(data-i18n='play_level.tip_first_language') The most disastrous thing that you can ever learn is your first programming language. - Alan Kay
|
||||||
strong.tip.rare
|
strong.tip.rare
|
||||||
span(data-i18n='play_level.tip_harry') Yer a Wizard,
|
span(data-i18n='play_level.tip_harry') Yer a Wizard,
|
||||||
span= me.get('name') || 'Anoner'
|
span= me.get('name', true)
|
||||||
|
|
||||||
.errors
|
.errors
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ module.exports = class AddLevelSystemModal extends ModalView
|
||||||
levelSystem =
|
levelSystem =
|
||||||
original: s.get('original') ? id
|
original: s.get('original') ? id
|
||||||
majorVersion: s.get('version').major ? 0
|
majorVersion: s.get('version').major ? 0
|
||||||
|
# TODO DEFAULTS
|
||||||
config: $.extend(true, {}, s.get('configSchema').default ? {})
|
config: $.extend(true, {}, s.get('configSchema').default ? {})
|
||||||
@extantSystems.push levelSystem
|
@extantSystems.push levelSystem
|
||||||
Backbone.Mediator.publish 'level-system-added', system: levelSystem
|
Backbone.Mediator.publish 'level-system-added', system: levelSystem
|
||||||
|
|
|
@ -72,6 +72,14 @@ 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')
|
||||||
|
jobProfile = @user.get('jobProfile')
|
||||||
|
jobProfile ?= {}
|
||||||
|
if not jobProfile.name
|
||||||
|
jobProfile.name = (@user.get('firstName') + ' ' + @user.get('lastName')).trim()
|
||||||
|
@user.set('jobProfile', jobProfile)
|
||||||
|
|
||||||
@highlightedContainers = []
|
@highlightedContainers = []
|
||||||
if me.isAdmin() or 'employer' in me.get('permissions')
|
if me.isAdmin() or 'employer' in me.get('permissions')
|
||||||
$.post "/db/user/#{me.id}/track/view_candidate"
|
$.post "/db/user/#{me.id}/track/view_candidate"
|
||||||
|
@ -223,16 +231,8 @@ module.exports = class JobProfileView extends UserView
|
||||||
context = super()
|
context = super()
|
||||||
context.userID = @userID
|
context.userID = @userID
|
||||||
context.linkedInAuthorized = @authorizedWithLinkedIn
|
context.linkedInAuthorized = @authorizedWithLinkedIn
|
||||||
context.jobProfileSchema = me.schema().properties.jobProfile
|
context.profile = @user.get('jobProfile', true)
|
||||||
if @user and not jobProfile = @user.get 'jobProfile'
|
context.rawProfile = @user.get('jobProfile') or {}
|
||||||
jobProfile = {}
|
|
||||||
for prop, schema of context.jobProfileSchema.properties
|
|
||||||
jobProfile[prop] = _.clone schema.default if schema.default?
|
|
||||||
for prop in context.jobProfileSchema.required
|
|
||||||
jobProfile[prop] ?= {string: '', boolean: false, number: 0, integer: 0, array: []}[context.jobProfileSchema.properties[prop].type]
|
|
||||||
@user.set 'jobProfile', jobProfile
|
|
||||||
jobProfile.name ?= (@user.get('firstName') + ' ' + @user.get('lastName')).trim() if @user?.get('firstName')
|
|
||||||
context.profile = jobProfile
|
|
||||||
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') or (context.myProfile && !me.get('anonymous')))
|
||||||
|
@ -244,7 +244,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
context.marked = marked
|
context.marked = marked
|
||||||
context.moment = moment
|
context.moment = moment
|
||||||
context.iconForLink = @iconForLink
|
context.iconForLink = @iconForLink
|
||||||
if links = jobProfile?.links
|
if links = context.profile.links
|
||||||
links = ($.extend(true, {}, link) for link in links)
|
links = ($.extend(true, {}, link) for link in links)
|
||||||
link.icon = @iconForLink link for link in links
|
link.icon = @iconForLink link for link in links
|
||||||
context.profileLinks = _.sortBy links, (link) -> not link.icon # icons first
|
context.profileLinks = _.sortBy links, (link) -> not link.icon # icons first
|
||||||
|
@ -290,8 +290,8 @@ module.exports = class JobProfileView extends UserView
|
||||||
aceUseWrapMode: true
|
aceUseWrapMode: true
|
||||||
callbacks: {change: @onRemarkChanged}
|
callbacks: {change: @onRemarkChanged}
|
||||||
@remarkTreema = @$el.find('#remark-treema').treema treemaOptions
|
@remarkTreema = @$el.find('#remark-treema').treema treemaOptions
|
||||||
@remarkTreema.build()
|
@remarkTreema?.build()
|
||||||
@remarkTreema.open(3)
|
@remarkTreema?.open(3)
|
||||||
|
|
||||||
onRemarkChanged: (e) =>
|
onRemarkChanged: (e) =>
|
||||||
return unless @remarkTreema.isValid()
|
return unless @remarkTreema.isValid()
|
||||||
|
@ -440,7 +440,8 @@ module.exports = class JobProfileView extends UserView
|
||||||
$(@).remove() if isEmpty @
|
$(@).remove() if isEmpty @
|
||||||
resetOnce = false # We have to clear out arrays if we're going to redo them
|
resetOnce = false # We have to clear out arrays if we're going to redo them
|
||||||
serialized = form.serializeArray()
|
serialized = form.serializeArray()
|
||||||
jobProfile = @user.get 'jobProfile'
|
jobProfile = @user.get('jobProfile') or {}
|
||||||
|
jobProfile[prop] ?= [] for prop in ['links', 'skills', 'work', 'education', 'projects']
|
||||||
rootPropertiesSeen = {}
|
rootPropertiesSeen = {}
|
||||||
for field in serialized
|
for field in serialized
|
||||||
keyChain = @extractFieldKeyChain field.name
|
keyChain = @extractFieldKeyChain field.name
|
||||||
|
@ -449,6 +450,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
for key, i in keyChain
|
for key, i in keyChain
|
||||||
rootPropertiesSeen[key] = true unless i
|
rootPropertiesSeen[key] = true unless i
|
||||||
break if i is keyChain.length - 1
|
break if i is keyChain.length - 1
|
||||||
|
parent[key] ?= {}
|
||||||
child = parent[key]
|
child = parent[key]
|
||||||
if _.isArray(child) and not resetOnce
|
if _.isArray(child) and not resetOnce
|
||||||
child = parent[key] = []
|
child = parent[key] = []
|
||||||
|
@ -467,6 +469,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
if section.hasClass('projects-container') and not section.find('.array-item').length
|
if section.hasClass('projects-container') and not section.find('.array-item').length
|
||||||
jobProfile.projects = []
|
jobProfile.projects = []
|
||||||
section.addClass 'saving'
|
section.addClass 'saving'
|
||||||
|
@user.set('jobProfile', jobProfile)
|
||||||
@saveEdits true
|
@saveEdits true
|
||||||
|
|
||||||
extractFieldKeyChain: (key) ->
|
extractFieldKeyChain: (key) ->
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
"jsondiffpatch": "~0.1.5",
|
"jsondiffpatch": "~0.1.5",
|
||||||
"nanoscroller": "~0.8.0",
|
"nanoscroller": "~0.8.0",
|
||||||
"jquery.tablesorter": "~2.15.13",
|
"jquery.tablesorter": "~2.15.13",
|
||||||
"treema": "~0.1.2",
|
"treema": "https://github.com/codecombat/treema.git#release/0.1.0",
|
||||||
"bootstrap": "~3.1.1",
|
"bootstrap": "~3.1.1",
|
||||||
"validated-backbone-mediator": "~0.1.3",
|
"validated-backbone-mediator": "~0.1.3",
|
||||||
"jquery.browser": "~0.0.6",
|
"jquery.browser": "~0.0.6",
|
||||||
|
|
|
@ -25,6 +25,7 @@ AchievementSchema.methods.stringifyQuery = ->
|
||||||
@set('query', JSON.stringify(@get('query'))) if typeof @get('query') != 'string'
|
@set('query', JSON.stringify(@get('query'))) if typeof @get('query') != 'string'
|
||||||
|
|
||||||
AchievementSchema.methods.getExpFunction = ->
|
AchievementSchema.methods.getExpFunction = ->
|
||||||
|
# TODO DEFAULTS
|
||||||
kind = @get('function')?.kind or jsonschema.properties.function.default.kind
|
kind = @get('function')?.kind or jsonschema.properties.function.default.kind
|
||||||
parameters = @get('function')?.parameters or jsonschema.properties.function.default.parameters
|
parameters = @get('function')?.parameters or jsonschema.properties.function.default.parameters
|
||||||
return utils.functionCreators[kind](parameters) if kind of utils.functionCreators
|
return utils.functionCreators[kind](parameters) if kind of utils.functionCreators
|
||||||
|
|
|
@ -12,12 +12,6 @@ LevelSchema.plugin(plugins.VersionedPlugin)
|
||||||
LevelSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
LevelSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
||||||
LevelSchema.plugin(plugins.PatchablePlugin)
|
LevelSchema.plugin(plugins.PatchablePlugin)
|
||||||
|
|
||||||
LevelSchema.pre 'init', (next) ->
|
|
||||||
return next() unless jsonschema.properties?
|
|
||||||
for prop, sch of jsonschema.properties
|
|
||||||
@set(prop, _.cloneDeep(sch.default)) if sch.default?
|
|
||||||
next()
|
|
||||||
|
|
||||||
LevelSchema.post 'init', (doc) ->
|
LevelSchema.post 'init', (doc) ->
|
||||||
if _.isString(doc.get('nextLevel'))
|
if _.isString(doc.get('nextLevel'))
|
||||||
doc.set('nextLevel', undefined)
|
doc.set('nextLevel', undefined)
|
||||||
|
|
|
@ -13,10 +13,4 @@ LevelComponentSchema.plugin plugins.VersionedPlugin
|
||||||
LevelComponentSchema.plugin plugins.SearchablePlugin, {searchable: ['name', 'description', 'system']}
|
LevelComponentSchema.plugin plugins.SearchablePlugin, {searchable: ['name', 'description', 'system']}
|
||||||
LevelComponentSchema.plugin plugins.PatchablePlugin
|
LevelComponentSchema.plugin plugins.PatchablePlugin
|
||||||
|
|
||||||
LevelComponentSchema.pre 'init', (next) ->
|
|
||||||
return next() unless jsonschema.properties?
|
|
||||||
for prop, sch of jsonschema.properties
|
|
||||||
@set(prop, _.cloneDeep sch.default) if sch.default?
|
|
||||||
next()
|
|
||||||
|
|
||||||
module.exports = LevelComponent = mongoose.model('level.component', LevelComponentSchema)
|
module.exports = LevelComponent = mongoose.model('level.component', LevelComponentSchema)
|
||||||
|
|
|
@ -14,13 +14,6 @@ LevelSessionSchema = new mongoose.Schema({
|
||||||
LevelSessionSchema.plugin(plugins.PermissionsPlugin)
|
LevelSessionSchema.plugin(plugins.PermissionsPlugin)
|
||||||
LevelSessionSchema.plugin(AchievablePlugin)
|
LevelSessionSchema.plugin(AchievablePlugin)
|
||||||
|
|
||||||
LevelSessionSchema.pre 'init', (next) ->
|
|
||||||
# TODO: refactor this into a set of common plugins for all models?
|
|
||||||
return next() unless jsonschema.properties?
|
|
||||||
for prop, sch of jsonschema.properties
|
|
||||||
@set(prop, _.cloneDeep(sch.default)) if sch.default?
|
|
||||||
next()
|
|
||||||
|
|
||||||
previous = {}
|
previous = {}
|
||||||
|
|
||||||
LevelSessionSchema.post 'init', (doc) ->
|
LevelSessionSchema.post 'init', (doc) ->
|
||||||
|
|
|
@ -12,10 +12,4 @@ LevelSystemSchema.plugin(plugins.VersionedPlugin)
|
||||||
LevelSystemSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
LevelSystemSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
||||||
LevelSystemSchema.plugin(plugins.PatchablePlugin)
|
LevelSystemSchema.plugin(plugins.PatchablePlugin)
|
||||||
|
|
||||||
LevelSystemSchema.pre 'init', (next) ->
|
|
||||||
return next() unless jsonschema.properties?
|
|
||||||
for prop, sch of jsonschema.properties
|
|
||||||
@set(prop, _.cloneDeep sch.default) if sch.default?
|
|
||||||
next()
|
|
||||||
|
|
||||||
module.exports = LevelSystem = mongoose.model('level.system', LevelSystemSchema)
|
module.exports = LevelSystem = mongoose.model('level.system', LevelSystemSchema)
|
||||||
|
|
|
@ -15,14 +15,6 @@ UserSchema = new mongoose.Schema({
|
||||||
'default': Date.now
|
'default': Date.now
|
||||||
}, {strict: false})
|
}, {strict: false})
|
||||||
|
|
||||||
UserSchema.pre('init', (next) ->
|
|
||||||
return next() unless jsonschema.properties?
|
|
||||||
for prop, sch of jsonschema.properties
|
|
||||||
continue if prop is 'emails' # defaults may change, so don't carry them over just yet
|
|
||||||
@set(prop, sch.default) if sch.default?
|
|
||||||
next()
|
|
||||||
)
|
|
||||||
|
|
||||||
UserSchema.post('init', ->
|
UserSchema.post('init', ->
|
||||||
@set('anonymous', false) if @get('email')
|
@set('anonymous', false) if @get('email')
|
||||||
)
|
)
|
||||||
|
|
|
@ -161,7 +161,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
post: (req, res) ->
|
post: (req, res) ->
|
||||||
return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
|
return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
|
||||||
return @sendBadInputError(res, 'Must have an anonymous user to post with.') unless req.user
|
return @sendBadInputError(res, 'Must have an anonymous user to post with.') unless req.user
|
||||||
return @sendBadInputError(res, 'Existing users cannot create new ones.') unless req.user.get('anonymous')
|
return @sendBadInputError(res, 'Existing users cannot create new ones.') if req.user.get('anonymous') is false
|
||||||
req.body._id = req.user._id if req.user.get('anonymous')
|
req.body._id = req.user._id if req.user.get('anonymous')
|
||||||
@put(req, res)
|
@put(req, res)
|
||||||
|
|
||||||
|
|
|
@ -14,3 +14,28 @@ describe 'UserModel', ->
|
||||||
|
|
||||||
me.set 'points', 50
|
me.set 'points', 50
|
||||||
expect(me.level()).toBe User.levelFromExp 50
|
expect(me.level()).toBe User.levelFromExp 50
|
||||||
|
|
||||||
|
describe 'user emails', ->
|
||||||
|
it 'has anyNotes, generalNews and recruitNotes enabled by default', ->
|
||||||
|
u = new User()
|
||||||
|
expect(u.get('emails')).toBeUndefined()
|
||||||
|
defaultEmails = u.get('emails', true)
|
||||||
|
expect(defaultEmails.anyNotes.enabled).toBe(true)
|
||||||
|
expect(defaultEmails.generalNews.enabled).toBe(true)
|
||||||
|
expect(defaultEmails.recruitNotes.enabled).toBe(true)
|
||||||
|
|
||||||
|
it 'maintains defaults of other emails when one is explicitly set', ->
|
||||||
|
u = new User()
|
||||||
|
u.setEmailSubscription('recruitNotes', false)
|
||||||
|
defaultEmails = u.get('emails', true)
|
||||||
|
expect(defaultEmails.anyNotes?.enabled).toBe(true)
|
||||||
|
expect(defaultEmails.generalNews?.enabled).toBe(true)
|
||||||
|
expect(defaultEmails.recruitNotes.enabled).toBe(false)
|
||||||
|
|
||||||
|
it 'does not populate raw data for other emails when one is explicitly set', ->
|
||||||
|
u = new User()
|
||||||
|
u.setEmailSubscription('recruitNotes', false)
|
||||||
|
u.buildAttributesWithDefaults()
|
||||||
|
emails = u.get('emails')
|
||||||
|
expect(emails.anyNotes).toBeUndefined()
|
||||||
|
expect(emails.generalNews).toBeUndefined()
|
||||||
|
|
|
@ -6,14 +6,14 @@ responses =
|
||||||
'/db/level.component/B/version/0': {
|
'/db/level.component/B/version/0': {
|
||||||
system: 'System'
|
system: 'System'
|
||||||
original: 'B'
|
original: 'B'
|
||||||
majorVersion: 0
|
version: {major: 0, minor:0}
|
||||||
name: 'B (depends on A)'
|
name: 'B (depends on A)'
|
||||||
dependencies: [{original:'A', majorVersion: 0}]
|
dependencies: [{original:'A', majorVersion: 0}]
|
||||||
}
|
}
|
||||||
'/db/level.component/A/version/0': {
|
'/db/level.component/A/version/0': {
|
||||||
system: 'System'
|
system: 'System'
|
||||||
original: 'A'
|
original: 'A'
|
||||||
majorVersion: 0
|
version: {major: 0, minor:0}
|
||||||
name: 'A'
|
name: 'A'
|
||||||
configSchema: { type: 'object', properties: { propA: { type: 'number' }, propB: { type: 'string' }} }
|
configSchema: { type: 'object', properties: { propA: { type: 'number' }, propB: { type: 'string' }} }
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ responses =
|
||||||
componentC = new LevelComponent({
|
componentC = new LevelComponent({
|
||||||
system: 'System'
|
system: 'System'
|
||||||
original: 'C'
|
original: 'C'
|
||||||
majorVersion: 0
|
version: {major: 0, minor:0}
|
||||||
name: 'C (depends on B)'
|
name: 'C (depends on B)'
|
||||||
dependencies: [{original:'B', majorVersion: 0}]
|
dependencies: [{original:'B', majorVersion: 0}]
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
JobProfileView = require 'views/account/JobProfileView'
|
JobProfileView = require 'views/user/JobProfileView'
|
||||||
|
|
||||||
responses =
|
responses =
|
||||||
'/db/user/joe/nameToID':'512ef4805a67a8c507000001'
|
'/db/user/joe/nameToID':'512ef4805a67a8c507000001'
|
||||||
|
|
Reference in a new issue