Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-04-23 10:22:29 -07:00
commit 50095a1778
17 changed files with 102 additions and 37 deletions

View file

@ -68,7 +68,7 @@ expandFlattenedDelta = (delta, left, schema) ->
parentLeft = left
parentSchema = schema
for key, i in delta.dataPath
# TODO: A more comprehensive way of getting child schemas
# TODO: Better schema/json walking
childSchema = parentSchema?.items or parentSchema?.properties?[key] or {}
childLeft = parentLeft?[key]
humanKey = null

View file

@ -69,25 +69,18 @@ module.exports.thangNames = thangNames =
"Buffy"
"Allankrita"
]
"Peasant": [
"Peasant M": [
"Yorik"
"Hector"
"Thad"
"Victor"
"Lyle"
"Charles"
"Mary"
"Brandy"
"Gwendolin"
"Tabitha"
"Regan"
"Yusef"
"Hingle"
"Azgot"
"Piers"
"Carlton"
"Giselle"
"Bernadette"
"Hershell"
"Gawain"
"Durfkor"
@ -99,6 +92,13 @@ module.exports.thangNames = thangNames =
"Icey"
"Matilda"
"Mertia"
"Mary"
"Brandy"
"Gwendolin"
"Tabitha"
"Regan"
"Giselle"
"Bernadette"
]
"Archer F": [
"Phoebe"

View file

@ -8,7 +8,7 @@ class Vector
a.copy()[name](b, useZ)
isVector: true
apiProperties: ['x', 'y', 'magnitude', 'heading', 'distance', 'dot', 'equals', 'copy']
apiProperties: ['x', 'y', 'magnitude', 'heading', 'distance', 'dot', 'equals', 'copy', 'distanceSquared']
constructor: (@x=0, @y=0, @z=0) ->

View file

@ -1,11 +1,11 @@
module.exports = nativeDescription: "Nederlands (België)", englishDescription: "Dutch (Belgium)", translation:
common:
loading: "Aan het laden..."
loading: "Bezig met laden..."
saving: "Opslaan..."
sending: "Verzenden..."
send: "Verzend"
cancel: "Annuleren"
save: "Opslagen"
save: "Opslaan"
publish: "Publiceren"
create: "Creëer"
delay_1_sec: "1 seconde"
@ -46,7 +46,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription:
employers: "Werkgevers"
versions:
save_version_title: "Nieuwe versie opslagen"
save_version_title: "Nieuwe versie opslaan"
new_major_version: "Nieuwe hoofd versie"
cla_prefix: "Om bewerkingen op te slaan, moet je eerst akkoord gaan met onze"
cla_url: "CLA"
@ -308,7 +308,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription:
editor:
main_title: "CodeCombat Editors"
main_description: "Maak je eigen levels, campagnes, eenheden en leermateriaal. Wij bieden alle programma's aan die u nodig heeft!"
main_description: "Maak je eigen levels, campagnes, eenheden en leermateriaal. Wij bieden alle programma's aan die je nodig hebt!"
article_title: "Artikel Editor"
article_description: "Schrijf artikels die spelers een overzicht geven over programmeer concepten die kunnen gebruikt worden over een variëteit van levels en campagnes."
thang_title: "Thang Editor"

View file

@ -1,11 +1,11 @@
module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription: "Dutch (Netherlands)", translation:
common:
loading: "Aan het laden..."
loading: "Bezig met laden..."
saving: "Opslaan..."
sending: "Verzenden..."
send: "Verzend"
cancel: "Annuleren"
save: "Opslagen"
save: "Opslaan"
publish: "Publiceren"
create: "Creëer"
delay_1_sec: "1 seconde"
@ -46,7 +46,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
employers: "Werkgevers"
versions:
save_version_title: "Nieuwe versie opslagen"
save_version_title: "Nieuwe versie opslaan"
new_major_version: "Nieuwe hoofd versie"
cla_prefix: "Om bewerkingen op te slaan, moet je eerst akkoord gaan met onze"
cla_url: "CLA"
@ -308,7 +308,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
editor:
main_title: "CodeCombat Editors"
main_description: "Maak je eigen levels, campagnes, eenheden en leermateriaal. Wij bieden alle programma's aan die u nodig heeft!"
main_description: "Maak je eigen levels, campagnes, eenheden en leermateriaal. Wij bieden alle programma's aan die je nodig hebt!"
article_title: "Artikel Editor"
article_description: "Schrijf artikels die spelers een overzicht geven over programmeer concepten die kunnen gebruikt worden over een variëteit van levels en campagnes."
thang_title: "Thang Editor"

View file

@ -1,11 +1,11 @@
module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", translation:
common:
loading: "Aan het laden..."
loading: "Bezig met laden..."
saving: "Opslaan..."
sending: "Verzenden..."
send: "Verzend"
cancel: "Annuleren"
save: "Opslagen"
save: "Opslaan"
publish: "Publiceren"
create: "Creëer"
delay_1_sec: "1 seconde"
@ -46,7 +46,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t
employers: "Werkgevers"
versions:
save_version_title: "Nieuwe versie opslagen"
save_version_title: "Nieuwe versie opslaan"
new_major_version: "Nieuwe hoofd versie"
cla_prefix: "Om bewerkingen op te slaan, moet je eerst akkoord gaan met onze"
cla_url: "CLA"
@ -308,7 +308,7 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t
editor:
main_title: "CodeCombat Editors"
main_description: "Maak je eigen levels, campagnes, eenheden en leermateriaal. Wij bieden alle programma's aan die u nodig heeft!"
main_description: "Maak je eigen levels, campagnes, eenheden en leermateriaal. Wij bieden alle programma's aan die je nodig hebt!"
article_title: "Artikel Editor"
article_description: "Schrijf artikels die spelers een overzicht geven over programmeer concepten die kunnen gebruikt worden over een variëteit van levels en campagnes."
thang_title: "Thang Editor"

View file

@ -133,6 +133,7 @@ class CocoModel extends Backbone.Model
schema ?= @schema()
models = []
# TODO: Better schema/json walking
if $.isArray(data) and schema.items?
for subData, i in data
models = models.concat(@getReferencedModels(subData, schema.items, path+i+'/', shouldLoadProjection))
@ -226,5 +227,27 @@ class CocoModel extends Backbone.Model
watching: ->
return me.id in (@get('watchers') or [])
populateI18N: (data, schema, path='') ->
# TODO: Better schema/json walking
sum = 0
data ?= $.extend true, {}, @attributes
schema ?= @schema() or {}
if schema.properties?.i18n and _.isPlainObject(data) and not data.i18n?
data.i18n = {}
sum += 1
if _.isPlainObject data
for key, value of data
numChanged = 0
numChanged = @populateI18N(value, childSchema, path+'/'+key) if childSchema = schema.properties?[key]
if numChanged and not path # should only do this for the root object
@set key, value
sum += numChanged
if schema.items and _.isArray data
sum += @populateI18N(value, schema.items, path+'/'+index) for value, index in data
sum
module.exports = CocoModel

View file

@ -68,6 +68,8 @@ block header
a(data-i18n="common.fork")#fork-level-start-button Fork
li(class=anonymous ? "disabled": "")
a(data-toggle="coco-modal", data-target="modal/revert", data-i18n="editor.revert")#revert-button Revert
li(class=anonymous ? "disabled": "")
a(data-i18n="editor.pop_i18n")#pop-level-i18n-button Populate i18n
li.divider
li.dropdown-header Info
li#level-history-button

View file

@ -28,6 +28,7 @@ block content
th(data-i18n="employers.candidate_last_updated") Last Updated
if me.isAdmin()
th ✓?
th ಥ_ಥ
tbody
for candidate, index in candidates
@ -57,4 +58,8 @@ block content
if candidate.get('jobProfileApproved')
td ✓
else
td ✗
td ✗
if profile.active
td ᶘ ᵒᴥᵒᶅ
else
td ⨂_⨂

View file

@ -233,6 +233,7 @@ class InternationalizationNode extends TreemaNode.nodeMap.object
type: "object"
properties: {}
}
return i18nChildSchema unless @parent
unless @schema.props?
console.warn "i18n props array is empty! Filling with all parent properties by default"
@schema.props = (prop for prop,_ of @parent.schema.properties when prop isnt "i18n")

View file

@ -40,6 +40,7 @@ module.exports = class ThangComponentEditView extends CocoView
@render()
buildExtantComponentTreema: ->
new Level() # hack to load the schema
treemaOptions =
supermodel: @supermodel
schema: Level.schema.properties.thangs.items.properties.components

View file

@ -31,6 +31,7 @@ module.exports = class EditorLevelView extends View
'click #patches-tab': -> @patchesView.load()
'click #level-patch-button': 'startPatchingLevel'
'click #level-watch-button': 'toggleWatchLevel'
'click #pop-level-i18n-button': -> @level.populateI18N()
constructor: (options, @levelID) ->
super options

View file

@ -77,7 +77,8 @@ grabUser = (session, callback) ->
totalEmailsSent = 0
emailUser = (user, callback) ->
return callback null, false if user.emails?.recruiting?.enabled is false # TODO: later, obey also "announcements" when that's untangled
#return callback null, false if user.emails?.anyNotes?.enabled is false # TODO: later, uncomment to obey also "anyNotes" when that's untangled
return callback null, false if user.emails?.recruitNotes?.enabled is false
return callback null, false if user.email in alreadyEmailed
return callback null, false if DEBUGGING and (totalEmailsSent > 1 or Math.random() > 0.1)
++totalEmailsSent

View file

@ -132,14 +132,24 @@ module.exports.setup = (app) ->
return errors.notFound res, "No user found with email '#{req.query.email}'"
emails = _.clone(user.get('emails')) or {}
emailSettings.enabled = false for emailSettings in _.values(emails)
emails.generalNews ?= {}
emails.generalNews.enabled = false
emails.anyNotes ?= {}
emails.anyNotes.enabled = false
user.update {$set: {emails: emails, emailSubscriptions: []}}, {}, =>
msg = ''
if req.query.recruitNotes
emails.recruitNotes ?= {}
emails.recruitNotes.enabled = false
msg = "Unsubscribed #{req.query.email} from recruiting emails."
else
msg = "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!"
emailSettings.enabled = false for emailSettings in _.values(emails)
emails.generalNews ?= {}
emails.generalNews.enabled = false
emails.anyNotes ?= {}
emails.anyNotes.enabled = false
user.update {$set: {emails: emails}}, {}, =>
return errors.serverError res, 'Database failure.' if err
res.send "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go! <p><a href='/account/settings'>Account settings</a></p>"
res.send msg + "<p><a href='/account/settings'>Account settings</a></p>"
res.end()
module.exports.loginUser = loginUser = (req, res, user, send=true, next=null) ->

View file

@ -47,7 +47,7 @@ UserSchema.methods.setEmailSubscription = (newName, enabled) ->
oldSubs.push(oldName) if enabled
@set('emailSubscriptions', oldSubs)
newSubs = _.clone(@get('emails') or jsonschema.properties.emails.default)
newSubs = _.clone(@get('emails') or _.cloneDeep(jsonschema.properties.emails.default))
newSubs[newName] ?= {}
newSubs[newName].enabled = enabled
@set('emails', newSubs)
@ -60,7 +60,7 @@ UserSchema.methods.isEmailSubscriptionEnabled = (newName) ->
oldName = emailNameMap[newName]
return oldName and oldName in oldSubs if oldSubs
emails ?= {}
_.defaults emails, jsonschema.properties.emails.default
_.defaults emails, _.cloneDeep(jsonschema.properties.emails.default)
return emails[newName]?.enabled
UserSchema.statics.updateMailChimp = (doc, callback) ->

View file

@ -235,9 +235,10 @@ UserHandler = class UserHandler extends Handler
getCandidates: (req, res) ->
authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions'))
since = (new Date((new Date()) - 2 * 30.4 * 86400 * 1000)).toISOString()
query = {'jobProfile.active': true, 'jobProfile.updated': {$gt: since}}
#query = {'jobProfile.updated': {$gt: since}}
#query = {'jobProfile.active': true, 'jobProfile.updated': {$gt: since}}
query = {'jobProfile.updated': {$gt: since}}
query.jobProfileApproved = true unless req.user.isAdmin()
query['jobProfile.active'] = true unless req.user.isAdmin()
selection = 'jobProfile'
selection += ' email' if authorized
selection += ' jobProfileApproved' if req.user.isAdmin()
@ -251,7 +252,7 @@ UserHandler = class UserHandler extends Handler
fields = if authorized then ['jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile']
obj = _.pick document.toObject(), fields
obj.photoURL ||= obj.jobProfile.photoURL if authorized
subfields = ['country', 'city', 'lookingFor', 'jobTitle', 'skills', 'experience', 'updated']
subfields = ['country', 'city', 'lookingFor', 'jobTitle', 'skills', 'experience', 'updated', 'active']
if authorized
subfields = subfields.concat ['name']
obj.jobProfile = _.pick obj.jobProfile, subfields

View file

@ -1,5 +1,6 @@
require '../common'
request = require 'request'
User = require '../../../server/users/User'
urlLogin = getURL('/auth/login')
urlReset = getURL('/auth/reset')
@ -16,7 +17,8 @@ describe '/auth/whoami', ->
describe '/auth/login', ->
it 'clears Users first', (done) ->
User.remove {}, (err) ->
clearModels [User], (err) ->
throw err if err
request.get getURL('/auth/whoami'), ->
throw err if err
done()
@ -134,3 +136,21 @@ describe '/auth/reset', ->
form = req.form()
form.append('username', 'scott@gmail.com')
form.append('password', 'nada')
describe '/auth/unsubscribe', ->
it 'clears Users first', (done) ->
clearModels [User], (err) ->
throw err if err
request.get getURL('/auth/whoami'), ->
throw err if err
done()
it 'removes just recruitment emails if you include ?recruitNotes=1', (done) ->
loginJoe (joe) ->
url = getURL('/auth/unsubscribe?recruitNotes=1&email='+joe.get('email'))
request.get url, (error, response) ->
expect(response.statusCode).toBe(200)
user = User.findOne(joe.get('_id')).exec (err, user) ->
expect(user.get('emails').recruitNotes.enabled).toBe(false)
expect(user.isEmailSubscriptionEnabled('generalNews')).toBeTruthy()
done()