From 27774cdf0fc53f4dba153831a7aaf528293ec1fd Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Mon, 23 Jun 2014 09:46:39 -0700 Subject: [PATCH 01/11] Fix #1207 --- app/views/account/profile_view.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/account/profile_view.coffee b/app/views/account/profile_view.coffee index 6f91cb5a6..f44aa802a 100644 --- a/app/views/account/profile_view.coffee +++ b/app/views/account/profile_view.coffee @@ -104,6 +104,7 @@ module.exports = class ProfileView extends View @linkedinLoaded = true if @waitingForLinkedIn @renderLinkedInButton() + @authorizedWithLinkedIn = IN?.User?.isAuthorized() renderLinkedInButton: => IN?.parse() From 815ef88e78d649b1a420ce91a0256fffa3da293e Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Mon, 23 Jun 2014 10:36:36 -0700 Subject: [PATCH 02/11] Fixed bugs with camera bobbing with bobbing units and gold views showing up when empty. --- app/lib/surface/Camera.coffee | 5 ++++- app/templates/play/ladder/ladder.jade | 6 +++++- app/views/account/profile_view.coffee | 1 + app/views/play/level/gold_view.coffee | 6 ++++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/lib/surface/Camera.coffee b/app/lib/surface/Camera.coffee index 80817afb4..cfbea59fb 100644 --- a/app/lib/surface/Camera.coffee +++ b/app/lib/surface/Camera.coffee @@ -288,10 +288,13 @@ module.exports = class Camera extends CocoClass boundTarget: (pos, zoom) -> # Given an {x, y} in Surface coordinates, return one that will keep our viewport on the Surface. return pos unless @bounds + y = pos.y + if thang = pos.sprite?.thang + y = @worldToSurface(x: thang.pos.x, y: thang.pos.y).y # ignore z marginX = (@canvasWidth / zoom / 2) marginY = (@canvasHeight / zoom / 2) x = Math.min(Math.max(marginX + @bounds.x, pos.x + @offset.x), @bounds.x + @bounds.width - marginX) - y = Math.min(Math.max(marginY + @bounds.y, pos.y + @offset.y), @bounds.y + @bounds.height - marginY) + y = Math.min(Math.max(marginY + @bounds.y, y + @offset.y), @bounds.y + @bounds.height - marginY) {x: x, y: y} updateViewports: (target) -> diff --git a/app/templates/play/ladder/ladder.jade b/app/templates/play/ladder/ladder.jade index 42f55cf29..3e042df50 100644 --- a/app/templates/play/ladder/ladder.jade +++ b/app/templates/play/ladder/ladder.jade @@ -22,7 +22,11 @@ block content p strong Tournament ended! a(href="#winners") Behold the winners - | . Thanks for playing! + | . Thanks for playing! You can + strong still play + | Greed and all of our other + a(href="/play/ladder") multiplayer arenas + | . p | Want to commiserate? Head over to a(href="http://discourse.codecombat.com/") the forum diff --git a/app/views/account/profile_view.coffee b/app/views/account/profile_view.coffee index f44aa802a..ca3329595 100644 --- a/app/views/account/profile_view.coffee +++ b/app/views/account/profile_view.coffee @@ -22,6 +22,7 @@ adminContacts = [ {id: "5162fab9c92b4c751e000274", name: "Scott"} {id: "51eb2714fa058cb20d0006ef", name: "Michael"} {id: "51538fdb812dd9af02000001", name: "George"} + {id: "52a57252a89409700d0000d9", name: "Ignore"} ] module.exports = class ProfileView extends View diff --git a/app/views/play/level/gold_view.coffee b/app/views/play/level/gold_view.coffee index d8faf7df1..01cde9f21 100644 --- a/app/views/play/level/gold_view.coffee +++ b/app/views/play/level/gold_view.coffee @@ -14,9 +14,9 @@ module.exports = class GoldView extends View super options @teamGold = {} @teamGoldEarned = {} + @shownOnce = false onGoldChanged: (e) -> - @$el.show() return if @teamGold[e.team] is e.gold and @teamGoldEarned[e.team] is e.goldEarned @teamGold[e.team] = e.gold @teamGoldEarned[e.team] = e.goldEarned @@ -30,9 +30,11 @@ module.exports = class GoldView extends View text += " (#{e.goldEarned})" goldEl.text text @updateTitle() + @$el.show() + @shownOnce = true updateTitle: -> @$el.attr 'title', ("Team '#{team}' has #{gold} now of #{@teamGoldEarned[team]} gold earned." for team, gold of @teamGold).join ' ' onSetLetterbox: (e) -> - @$el.toggle not e.on + @$el.toggle not e.on if @shownOnce From dde43d5df3bd28b88aa14bf31c386084e4c92902 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Mon, 23 Jun 2014 16:56:32 -0400 Subject: [PATCH 03/11] Fixed a case where the supermodel was overriding what a previous supermodel had set for saveBackups. --- app/models/SuperModel.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/SuperModel.coffee b/app/models/SuperModel.coffee index c5a4eeb55..7fd98ded5 100644 --- a/app/models/SuperModel.coffee +++ b/app/models/SuperModel.coffee @@ -122,7 +122,7 @@ module.exports = class SuperModel extends Backbone.Model return @progress is 1.0 or not @denom addModelResource: (modelOrCollection, name, fetchOptions, value=1) -> - modelOrCollection.saveBackups = @shouldSaveBackups(modelOrCollection) + modelOrCollection.saveBackups = modelOrCollection.saveBackups or @shouldSaveBackups(modelOrCollection) @checkName(name) res = new ModelResource(modelOrCollection, name, fetchOptions, value) @storeResource(res, value) From 9a571a6fe73d4c800341d0af80a9400845f7e7a0 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Tue, 24 Jun 2014 11:55:04 -0400 Subject: [PATCH 04/11] Fixed the file not 'changing' when overwritten. It was a caching issue. --- server/routes/file.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/routes/file.coffee b/server/routes/file.coffee index e96a2453a..abb5302e8 100644 --- a/server/routes/file.coffee +++ b/server/routes/file.coffee @@ -130,6 +130,8 @@ checkExistence = (options, req, res, force, done) -> errors.conflict(res, {canForce:userCanEditFile(req.user, file)}) done(true) else if file + fullPath = "/file/#{options.metadata.path}/#{options.filename}" + clearCloudFlareCacheForFile(fullPath) q = { _id: file._id } q.root = 'media' Grid.gfs.remove q, (err) -> @@ -172,3 +174,16 @@ createPostOptions = (req) -> options.metadata.description = req.body.description if req.body.description? options + +clearCloudFlareCacheForFile = (path='/file') -> + request = require 'request' + r = request.post 'https://www.cloudflare.com/api_json.html', (err, httpResponse, body) -> + if (err) + console.error('CloudFlare file cache clear failed:', body) + + form = r.form() + form.append 'tkn', 'dea38682b209901a014dba2b2702afa5476a0' + form.append 'email', 'scott@codecombat.com' + form.append 'z', 'codecombat.com' + form.append 'a', 'zone_file_purge' + form.append 'url', "http://codecombat.com#{path}" From 573b5665800e67858d0c875437b1e4b74b88b277 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Tue, 24 Jun 2014 12:29:47 -0400 Subject: [PATCH 05/11] Fixed the cloudflare config to be in the environmental variables. --- server/routes/file.coffee | 7 ++++++- server_config.coffee | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/server/routes/file.coffee b/server/routes/file.coffee index abb5302e8..8406dd462 100644 --- a/server/routes/file.coffee +++ b/server/routes/file.coffee @@ -3,6 +3,7 @@ fs = require 'fs' request = require 'request' mongoose = require('mongoose') errors = require '../commons/errors' +config = require '../../server_config' module.exports.setup = (app) -> app.all '/file*', (req, res) -> @@ -176,13 +177,17 @@ createPostOptions = (req) -> options clearCloudFlareCacheForFile = (path='/file') -> + unless config.cloudflare.token + console.log 'skipping clearing cloud cache, not configured' + return + request = require 'request' r = request.post 'https://www.cloudflare.com/api_json.html', (err, httpResponse, body) -> if (err) console.error('CloudFlare file cache clear failed:', body) form = r.form() - form.append 'tkn', 'dea38682b209901a014dba2b2702afa5476a0' + form.append 'tkn', config.cloudflare.token form.append 'email', 'scott@codecombat.com' form.append 'z', 'codecombat.com' form.append 'a', 'zone_file_purge' diff --git a/server_config.coffee b/server_config.coffee index ec3c38dfd..7741825cf 100644 --- a/server_config.coffee +++ b/server_config.coffee @@ -4,6 +4,8 @@ config.unittest = process.argv.indexOf("--unittest") > -1 config.port = process.env.COCO_PORT or process.env.COCO_NODE_PORT or 3000 config.ssl_port = process.env.COCO_SSL_PORT or process.env.COCO_SSL_NODE_PORT or 3443 +config.cloudflare = + token: process.env.COCO_CLOUDFLARE_API_KEY or '' config.mongo = port: process.env.COCO_MONGO_PORT or 27017 From 3862bd23763efcabfbb7063cc9cdef33a70bef76 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Mon, 23 Jun 2014 18:25:58 -0700 Subject: [PATCH 06/11] Clearing backups of old models when saving new versions of versioned models. --- app/templates/play/level/goals.jade | 2 +- app/views/editor/article/edit.coffee | 3 ++- app/views/editor/level/save_view.coffee | 4 +++- app/views/editor/thang/edit.coffee | 8 +++++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/templates/play/level/goals.jade b/app/templates/play/level/goals.jade index 51d64f23b..d1e0b689c 100644 --- a/app/templates/play/level/goals.jade +++ b/app/templates/play/level/goals.jade @@ -1,7 +1,7 @@ ul#primary-goals-list div.goals-status strong(data-i18n="play_level.goals") Goals - span.spl.spr : + span.spr : span(data-i18n="play_level.success").secret.goal-status.success Success! span(data-i18n="play_level.incomplete").secret.goal-status.incomplete Incomplete span(data-i18n="play_level.timed_out").secret.goal-status.timed-out Ran out of time diff --git a/app/views/editor/article/edit.coffee b/app/views/editor/article/edit.coffee index c165c9701..5a319bd06 100644 --- a/app/views/editor/article/edit.coffee +++ b/app/views/editor/article/edit.coffee @@ -81,7 +81,7 @@ module.exports = class ArticleEditView extends View @preview.focus() if window.focus @preview.onload = => @pushChangesToPreview() return false - + openSaveModal: -> @openModalView(new SaveVersionModal({model: @article})) @@ -101,6 +101,7 @@ module.exports = class ArticleEditView extends View @disableModalInProgress(modal) res.success => + @article.clearBackup() modal.modal('hide') url = "/editor/article/#{newArticle.get('slug') or newArticle.id}" document.location.href = url diff --git a/app/views/editor/level/save_view.coffee b/app/views/editor/level/save_view.coffee index 4516cc44d..6f0f6f18e 100644 --- a/app/views/editor/level/save_view.coffee +++ b/app/views/editor/level/save_view.coffee @@ -76,7 +76,7 @@ module.exports = class LevelSaveView extends SaveVersionModal else if @level.isPublished() and not newModel.isPublished() newModel.publish() # Publish any LevelComponents that weren't published yet formsToSave.push form - + for model in modelsToSave if errors = model.getValidationErrors() messages = ("\t #{error.dataPath}: #{error.message}" for error in errors) @@ -96,6 +96,8 @@ module.exports = class LevelSaveView extends SaveVersionModal forms.applyErrorsToForm($(form), JSON.parse(res.responseText)) res.success => modelsToSave = _.without modelsToSave, newModel + oldModel = _.find @supermodel.models, (m) -> m.get('original') is newModel.get('original') + oldModel.clearBackup() # Otherwise looking at old versions is confusing. unless modelsToSave.length url = "/editor/level/#{@level.get('slug') or @level.id}" document.location.href = url diff --git a/app/views/editor/thang/edit.coffee b/app/views/editor/thang/edit.coffee index 3d753ff50..0880fbff4 100644 --- a/app/views/editor/thang/edit.coffee +++ b/app/views/editor/thang/edit.coffee @@ -66,7 +66,7 @@ module.exports = class ThangTypeEditView extends View raw = ("raw:#{name}" for name in raw) main = _.keys(@thangType.get('actions') or {}) main.concat(raw) - + afterRender: -> super() return unless @supermodel.finished() @@ -326,7 +326,9 @@ module.exports = class ThangTypeEditView extends View image = @currentSprite.imageObject.image portraitSource = imageToPortrait image # bit of a hacky way to get that portrait - success = -> document.location.href = url + success = => + @thangType.clearBackup() + document.location.href = url newThangType.uploadGenericPortrait success, portraitSource clearRawData: -> @@ -419,4 +421,4 @@ imageToPortrait = (img) -> scaleY = 100 / img.height ctx.scale scaleX, scaleY ctx.drawImage img, 0, 0 - canvas.toDataURL("image/png") \ No newline at end of file + canvas.toDataURL("image/png") From abcc75a6f2a4947c49efad82a223aadb7ca02169 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Tue, 24 Jun 2014 09:43:14 -0700 Subject: [PATCH 07/11] A bit of error logging for #1220. --- app/models/CocoModel.coffee | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index e2cefa09d..dd6ce23cf 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -64,7 +64,7 @@ class CocoModel extends Backbone.Model @backedUp = {} schema: -> return @constructor.schema - + getValidationErrors: -> errors = tv4.validateMultiple(@attributes, @constructor.schema or {}).errors return errors if errors?.length @@ -76,7 +76,7 @@ class CocoModel extends Backbone.Model for error in errors console.debug "\t", error.dataPath, ":", error.message return errors - + save: (attrs, options) -> options ?= {} options.headers ?= {} @@ -97,19 +97,19 @@ class CocoModel extends Backbone.Model noty text: "#{errorMessage}: #{res.status} #{res.statusText}", layout: 'topCenter', type: 'error', killer: false, timeout: 10000 @trigger "save", @ return super attrs, options - + patch: (options) -> return false unless @_revertAttributes options ?= {} options.patch = true - + attrs = {_id: @id} keys = [] for key in _.keys @attributes unless _.isEqual @attributes[key], @_revertAttributes[key] attrs[key] = @attributes[key] keys.push key - + return unless keys.length console.debug 'Patching', @get('name') or @, keys @save(attrs, options) @@ -207,7 +207,10 @@ class CocoModel extends Backbone.Model applyDelta: (delta) -> newAttributes = $.extend(true, {}, @attributes) - jsondiffpatch.patch newAttributes, delta + try + jsondiffpatch.patch newAttributes, delta + catch error + console.error "Error applying delta", delta, "to attributes", newAttributes, error @set newAttributes getExpandedDelta: -> From 8719b806637ee166c31b73beef3c0e003d1e0926 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Tue, 24 Jun 2014 10:15:38 -0700 Subject: [PATCH 08/11] Showing expired profiles to admins. --- app/styles/employers.sass | 3 +++ app/templates/employers.jade | 6 ++++-- server/users/user_handler.coffee | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/styles/employers.sass b/app/styles/employers.sass index 522785750..233dd5e10 100644 --- a/app/styles/employers.sass +++ b/app/styles/employers.sass @@ -49,6 +49,9 @@ tr cursor: pointer + tr.expired + opacity: 0.5 + code background-color: rgb(220, 220, 220) color: #555 diff --git a/app/templates/employers.jade b/app/templates/employers.jade index 208c2bdf7..a9140cd04 100644 --- a/app/templates/employers.jade +++ b/app/templates/employers.jade @@ -93,7 +93,9 @@ block content for candidate, index in area.candidates - var profile = candidate.get('jobProfile'); - var authorized = candidate.id; // If we have the id, then we are authorized. - tr(data-candidate-id=candidate.id, id=candidate.id) + - var profileAge = (new Date() - new Date(profile.updated)) / 86400 / 1000; + - var expired = profileAge > 2 * 30.4; + tr(data-candidate-id=candidate.id, id=candidate.id, class=expired ? "expired" : "") td if authorized img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=50) @@ -115,7 +117,7 @@ block content code= skill span td= profile.experience - td(data-profile-age=(new Date() - new Date(profile.updated)) / 86400 / 1000)= moment(profile.updated).fromNow() + td(data-profile-age=profileAge)= moment(profile.updated).fromNow() if me.isAdmin() td= remarks[candidate.id] ? remarks[candidate.id].get('contactName') : '' if me.isAdmin() && area.id == 'inactive-candidates' diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index 712318664..3bd3bed78 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -308,9 +308,9 @@ 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() + months = if req.user.isAdmin() then 12 else 2 + since = (new Date((new Date()) - months * 30.4 * 86400 * 1000)).toISOString() query = {'jobProfile.updated': {$gt: since}} - #query.jobProfileApproved = true unless req.user.isAdmin() # We split into featured and other now. query['jobProfile.active'] = true unless req.user.isAdmin() selection = 'jobProfile jobProfileApproved photoURL' selection += ' email name' if authorized From 6a31e0bcd3dd4f283102d73df93d25f5722739a5 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Tue, 24 Jun 2014 10:17:38 -0700 Subject: [PATCH 09/11] Fixed bug showing spell palette for languages missing any code snippets. --- app/views/play/level/tome/spell_view.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee index b2557c853..81f3bb4a1 100644 --- a/app/views/play/level/tome/spell_view.coffee +++ b/app/views/play/level/tome/spell_view.coffee @@ -180,8 +180,8 @@ module.exports = class SpellView extends View return (owner is 'this' or owner is 'more') and (not doc.owner? or doc.owner is 'this') console.log 'could not find doc for', prop, 'from', e.allDocs['__' + prop], 'for', owner, 'of', e.propGroups unless doc doc ?= prop - if doc.snippets? - entry = + if doc.snippets?[@spell.language] + entry = content: doc.snippets[@spell.language].code name: doc.name tabTrigger: doc.snippets[@spell.language].tab From 036316673682b9c89ae346447b73c826bb985c17 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Tue, 24 Jun 2014 13:22:57 -0400 Subject: [PATCH 10/11] Some tweaks to the guide for the benefit of the criss-cross docs, and hopefully others as well. --- app/styles/play/level/modal/docs.sass | 16 ++++++++++++++++ app/views/play/level/modal/docs_modal.coffee | 1 + 2 files changed, 17 insertions(+) diff --git a/app/styles/play/level/modal/docs.sass b/app/styles/play/level/modal/docs.sass index 2f833d8ef..51be8378d 100644 --- a/app/styles/play/level/modal/docs.sass +++ b/app/styles/play/level/modal/docs.sass @@ -1,5 +1,21 @@ #docs-modal .modal-dialog width: 800px + + .tab-content + padding-top: 20px li:not(.active) a[data-toggle="tab"] cursor: pointer + + img + display: block + margin: 0 auto + + em + display: block + margin: 0 auto + text-align: center + + hr + border-color: #5c5c5c + width: 80% \ No newline at end of file diff --git a/app/views/play/level/modal/docs_modal.coffee b/app/views/play/level/modal/docs_modal.coffee index 8c6a56a16..1df8975c0 100644 --- a/app/views/play/level/modal/docs_modal.coffee +++ b/app/views/play/level/modal/docs_modal.coffee @@ -8,6 +8,7 @@ utils = require 'lib/utils' module.exports = class DocsModal extends View template: template id: 'docs-modal' + plain: true shortcuts: 'enter': 'hide' From 988ad6ffda43ec66c20a02b4eaf058fc8f6d74e2 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Tue, 24 Jun 2014 11:29:43 -0700 Subject: [PATCH 11/11] Attempting to fix G+ --- app/lib/services/google.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/services/google.coffee b/app/lib/services/google.coffee index c664efb86..cf8e14af0 100644 --- a/app/lib/services/google.coffee +++ b/app/lib/services/google.coffee @@ -1,8 +1,8 @@ module.exports = initializeGoogle = -> - onGPlusLoaded = -> + window.onGPlusLoaded = -> Backbone.Mediator.publish "gapi-loaded" return - signinCallback = (authResult) -> + window.signinCallback = (authResult) -> Backbone.Mediator.publish "gplus-logged-in", authResult if authResult["access_token"] return (->