From 15d89789f22069e78709b6627a2a02ac31d44968 Mon Sep 17 00:00:00 2001 From: Fergus Leen Date: Mon, 16 Jun 2014 21:48:27 +0100 Subject: [PATCH 1/9] Checks for false positive 64 bit --- scripts/devSetup/systemConfiguration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/devSetup/systemConfiguration.py b/scripts/devSetup/systemConfiguration.py index c8b2b99de..78df92fdf 100644 --- a/scripts/devSetup/systemConfiguration.py +++ b/scripts/devSetup/systemConfiguration.py @@ -33,6 +33,8 @@ class SystemConfiguration(object): return 64 else: if self.operating_system == u"mac": + if os.uname()[4] == u"x86_64": + return 64 raise NotSupportedError(u"Your processor is determined to have a maxSize of" + str(sys.maxsize) + u",\n which doesn't correspond with a 64-bit architecture.") return 32 From 42304d8fb44984fd0fd05f91b3120798e846e74f Mon Sep 17 00:00:00 2001 From: Fergus Leen Date: Tue, 17 Jun 2014 19:30:32 +0100 Subject: [PATCH 2/9] Check for git repository before cloning --- scripts/devSetup/bootstrap.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/devSetup/bootstrap.sh b/scripts/devSetup/bootstrap.sh index 9d1f34b8e..46099635c 100644 --- a/scripts/devSetup/bootstrap.sh +++ b/scripts/devSetup/bootstrap.sh @@ -58,7 +58,13 @@ checkDependencies deps[@] basicDependenciesErrorHandling if command -v node >/dev/null 2>&1; then checkNodeVersion fi -#install git repository -git clone $repositoryUrl coco -#python ./coco/scripts/devSetup/setup.py -echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!" + +#check if a git repository already exists here +if [ -d .git ]; then + echo "A git repository already exists here!" +else + #install git repository + git clone $repositoryUrl coco + #python ./coco/scripts/devSetup/setup.py + echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!" +fi From de1f6ab50ae39c81dbab8c37bf9636c6aaa3ab9d Mon Sep 17 00:00:00 2001 From: Fergus Leen Date: Tue, 17 Jun 2014 19:44:32 +0100 Subject: [PATCH 3/9] Check for git repository before cloning --- scripts/devSetup/bootstrap.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/devSetup/bootstrap.sh b/scripts/devSetup/bootstrap.sh index 9d1f34b8e..46099635c 100644 --- a/scripts/devSetup/bootstrap.sh +++ b/scripts/devSetup/bootstrap.sh @@ -58,7 +58,13 @@ checkDependencies deps[@] basicDependenciesErrorHandling if command -v node >/dev/null 2>&1; then checkNodeVersion fi -#install git repository -git clone $repositoryUrl coco -#python ./coco/scripts/devSetup/setup.py -echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!" + +#check if a git repository already exists here +if [ -d .git ]; then + echo "A git repository already exists here!" +else + #install git repository + git clone $repositoryUrl coco + #python ./coco/scripts/devSetup/setup.py + echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!" +fi From ecf24c28754baf17c73d494f42ec72b2c4fcabbf Mon Sep 17 00:00:00 2001 From: Fergus Leen Date: Tue, 17 Jun 2014 19:56:13 +0100 Subject: [PATCH 4/9] Commit on wrong branch - reverted --- scripts/devSetup/bootstrap.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/scripts/devSetup/bootstrap.sh b/scripts/devSetup/bootstrap.sh index 46099635c..9d1f34b8e 100644 --- a/scripts/devSetup/bootstrap.sh +++ b/scripts/devSetup/bootstrap.sh @@ -58,13 +58,7 @@ checkDependencies deps[@] basicDependenciesErrorHandling if command -v node >/dev/null 2>&1; then checkNodeVersion fi - -#check if a git repository already exists here -if [ -d .git ]; then - echo "A git repository already exists here!" -else - #install git repository - git clone $repositoryUrl coco - #python ./coco/scripts/devSetup/setup.py - echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!" -fi +#install git repository +git clone $repositoryUrl coco +#python ./coco/scripts/devSetup/setup.py +echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!" From 4bd02ba6dc47358fc8fc86162228d8682cec5d6d Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Tue, 17 Jun 2014 15:17:19 -0700 Subject: [PATCH 5/9] ModelModal now grants real ultimate power. --- app/templates/account/profile.jade | 4 +++- app/templates/modal/model.jade | 6 ++++-- app/views/account/profile_view.coffee | 5 +++++ app/views/modal/model_modal.coffee | 27 +++++++++++++++++++++++++++ server/users/user_handler.coffee | 14 +++++--------- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/app/templates/account/profile.jade b/app/templates/account/profile.jade index 639d14d84..de9dcca11 100644 --- a/app/templates/account/profile.jade +++ b/app/templates/account/profile.jade @@ -43,7 +43,9 @@ block content i.icon-eye-close span(data-i18n='account_profile.not_featured') Not Featured if me.isAdmin() && !myProfile - button.btn.edit-settings-button#enter-espionage-mode 007 + button.btn#enter-espionage-mode 007 + if me.isAdmin() + button.btn#open-model-modal Raw if profile && allowedToViewJobProfile div(class="job-profile-container" + (editing ? " editable-profile" : "")) diff --git a/app/templates/modal/model.jade b/app/templates/modal/model.jade index 4fae4c294..404dfb571 100644 --- a/app/templates/modal/model.jade +++ b/app/templates/modal/model.jade @@ -4,6 +4,8 @@ block modal-header block modal-body-content for model in models - h3= model.type() + ': ' + model.id - .model-treema(data-model-id=model.id) + .model-container(data-model-id=model.id) + h3= model.type() + ': ' + model.id + .model-treema(data-model-id=model.id) + btn.btn.btn-success.save-model(data-i18n="common.save") Save hr diff --git a/app/views/account/profile_view.coffee b/app/views/account/profile_view.coffee index a4100808c..e67b7a8fb 100644 --- a/app/views/account/profile_view.coffee +++ b/app/views/account/profile_view.coffee @@ -8,6 +8,7 @@ JobProfileContactView = require 'views/modal/job_profile_contact_modal' JobProfileView = require 'views/account/job_profile_view' UserRemark = require 'models/UserRemark' forms = require 'lib/forms' +ModelModal = require 'views/modal/model_modal' class LevelSessionsCollection extends CocoCollection url: -> "/db/user/#{@userID}/level.sessions/employer" @@ -37,6 +38,7 @@ module.exports = class ProfileView extends View 'click #save-notes-button': 'onJobProfileNotesChanged' 'click #contact-candidate': 'onContactCandidate' 'click #enter-espionage-mode': 'enterEspionageMode' + 'click #open-model-modal': 'openModelModal' 'click .editable-profile .profile-photo': 'onEditProfilePhoto' 'click .editable-profile .project-image': 'onEditProjectImage' 'click .editable-profile .editable-display': 'onEditSection' @@ -340,6 +342,9 @@ module.exports = class ProfileView extends View espionageSuccess: (model) -> window.location.reload() + openModelModal: (e) -> + @openModalView new ModelModal models: [@user] + onJobProfileNotesChanged: (e) => notes = @$el.find("#job-profile-notes").val() @user.set 'jobProfileNotes', notes diff --git a/app/views/modal/model_modal.coffee b/app/views/modal/model_modal.coffee index e1f983247..7424d6822 100644 --- a/app/views/modal/model_modal.coffee +++ b/app/views/modal/model_modal.coffee @@ -6,6 +6,8 @@ module.exports = class ModelModal extends View template: template plain: true + events: 'click .save-model': 'onSaveModel' + constructor: (options) -> super options @models = options.models @@ -20,6 +22,7 @@ module.exports = class ModelModal extends View afterRender: -> return unless @supermodel.finished() + @modelTreemas = {} for model in @models data = $.extend true, {}, model.attributes schema = $.extend true, {}, model.schema() @@ -31,6 +34,7 @@ module.exports = class ModelModal extends View modelTreema?.build() modelTreema?.open() @openTastyTreemas modelTreema, model + @modelTreemas[model.id] = modelTreema openTastyTreemas: (modelTreema, model) -> # To save on quick inspection, let's auto-open the properties we're most likely to want to see. @@ -45,3 +49,26 @@ module.exports = class ModelModal extends View }[team] for dessert in desserts child.childrenTreemas[dessert]?.open() + + onSaveModel: (e) -> + container = $(e.target).closest('.model-container') + model = _.find @models, id: container.data('model-id') + treema = @modelTreemas[model.id] + changes = {} + for key, val of treema.data when not _.isEqual val, model.get key + console.log "Updating", key, "from", model.get(key), "to", val + model.set key, val + changes[key] = val + for key, val of model.attributes when treema.get(key) is undefined and not _.string.startsWith key, '_' + console.log "Deleting", key, "which was", val, "but man, that ain't going to work, now is it?" + #changes[key] = undefined + model.unset key + if errors = model.validate() + return console.warn model, "failed validation with errors:", errors + res = model.save changes, {patch: true} + res.error => + return if @destroyed + console.error model, "failed to save with error:", res.responseText + res.success (model, response, options) => + return if @destroyed + @hide() diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index a9e0dc106..af797f614 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -24,7 +24,7 @@ candidateProperties = [ UserHandler = class UserHandler extends Handler modelClass: User - + jsonSchema: schema editableProperties: [ 'name', 'photoURL', 'password', 'anonymous', 'wizardColor1', 'volume', 'firstName', 'lastName', 'gender', 'facebookID', 'gplusID', 'emails', @@ -32,15 +32,11 @@ UserHandler = class UserHandler extends Handler 'wizard', 'aceConfig', 'autocastDelay', 'lastLevel', 'jobProfile' ] - jsonSchema: schema - - constructor: -> - super(arguments...) - @editableProperties.push('permissions') unless config.isProduction - getEditableProperties: (req, document) -> props = super req, document - props.push 'jobProfileApproved', 'jobProfileNotes' if req.user.isAdmin() + props.push 'permissions' unless config.isProduction + props.push 'jobProfileApproved', 'jobProfileNotes' if req.user.isAdmin() # Admins naturally edit these + props.push privateProperties... if req.user.isAdmin() # Admins are mad with power props formatEntity: (req, document) -> @@ -344,7 +340,7 @@ UserHandler = class UserHandler extends Handler getEmployers: (req, res) -> return @sendUnauthorizedError(res) unless req.user.isAdmin() - query = {employerAt: {$exists: true}} + query = {employerAt: {$exists: true, $ne: ''}} selection = 'name firstName lastName email activity signedEmployerAgreement photoURL employerAt' User.find(query).select(selection).lean().exec (err, documents) => return @sendDatabaseError res, err if err From 59654da24bbce81cdafa0d6232bc184fb0179cff Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Tue, 17 Jun 2014 22:17:44 -0700 Subject: [PATCH 6/9] Starting more work on integrating additional languages. Improved Component code editing performance with a trusty debounce. --- app/views/editor/level/component/edit.coffee | 2 ++ .../editor/level/components_tab_view.coffee | 4 +-- app/views/play/level/tome/spell.coffee | 32 ++++++++++++------- app/views/play/level/tome/spell_view.coffee | 7 ++-- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/app/views/editor/level/component/edit.coffee b/app/views/editor/level/component/edit.coffee index 3bc526813..856f79a4d 100644 --- a/app/views/editor/level/component/edit.coffee +++ b/app/views/editor/level/component/edit.coffee @@ -25,6 +25,7 @@ module.exports = class LevelComponentEditView extends View super options @levelComponent = @supermodel.getModelByOriginalAndMajorVersion LevelComponent, options.original, options.majorVersion or 0 console.log "Couldn't get levelComponent for", options, "from", @supermodel.models unless @levelComponent + @onEditorChange = _.debounce @onEditorChange, 1500 getRenderData: (context={}) -> context = super(context) @@ -95,6 +96,7 @@ module.exports = class LevelComponentEditView extends View @editor.on('change', @onEditorChange) onEditorChange: => + return if @destroyed @levelComponent.set 'code', @editor.getValue() Backbone.Mediator.publish 'level-component-edited', levelComponent: @levelComponent null diff --git a/app/views/editor/level/components_tab_view.coffee b/app/views/editor/level/components_tab_view.coffee index a0fe32f94..0ae4a3873 100644 --- a/app/views/editor/level/components_tab_view.coffee +++ b/app/views/editor/level/components_tab_view.coffee @@ -35,13 +35,13 @@ module.exports = class ComponentsTabView extends View componentModels = @supermodel.getModels LevelComponent componentModelMap = {} - componentModelMap[comp.get('original')] = comp for comp in componentModels + componentModelMap[comp.get('original')] = comp for comp in componentModels components = ({original: key.split('.')[0], majorVersion: parseInt(key.split('.')[1], 10), thangs: value, count: value.length} for key, value of @presentComponents) treemaData = _.sortBy components, (comp) -> comp = componentModelMap[comp.original] res = [comp.get('system'), comp.get('name')] return res - + treemaOptions = supermodel: @supermodel schema: {type: 'array', items: {type: 'object', format: 'level-component'}} diff --git a/app/views/play/level/tome/spell.coffee b/app/views/play/level/tome/spell.coffee index 7c796482d..5e3501014 100644 --- a/app/views/play/level/tome/spell.coffee +++ b/app/views/play/level/tome/spell.coffee @@ -18,23 +18,19 @@ module.exports = class Spell @supermodel = options.supermodel @skipProtectAPI = options.skipProtectAPI @worker = options.worker - p = options.programmableMethod + p = options.programmableMethod + @languages = p.languages ? {} + @languages.javascript ?= p.source @name = p.name @permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams - teamSpells = @session.get('teamSpells') - team = @session.get('team') ? 'humans' - @useTranspiledCode = @permissions.readwrite.length and ((teamSpells and not _.contains(teamSpells[team], @spellKey)) or (@session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions'))) or @spectateView) - if @useTranspiledCode - console.log "#{@spellKey} is using transpiled code because permissions.readwrite is #{@permissions.readwrite} - #{if @spectateView then ', we are spectating' else ''} - #{if teamSpells and not _.contains(teamSpells[team], @spellKey) then ', teamSpells[' + team + '] does not have ' + @spellKey + ' (just ' + teamSpells[team] + ')' else ''} - #{if @session.get('creator') isnt me.id then ', and the session was created by ' + @session.get('creator') + ' but I am ' + me.id else ''}" - @source = @originalSource = p.source + @setLanguage if @canWrite() then options.language else 'javascript' + @useTranspiledCode = @shouldUseTranspiledCode() + + @source = @originalSource @parameters = p.parameters if @permissions.readwrite.length and sessionSource = @session.getSourceFor(@spellKey) @source = sessionSource - @language = if @canWrite() then options.language else 'javascript' @thangs = {} @view = new SpellView {spell: @, session: @session, worker: @worker} @view.render() # Get it ready and code loaded in advance @@ -49,6 +45,9 @@ module.exports = class Spell @thangs = null @worker = null + setLanguage: (@language) -> + @originalSource = @languages[language] ? @languages.javascript + addThang: (thang) -> if @thangs[thang.id] @thangs[thang.id].thang = thang @@ -155,3 +154,14 @@ module.exports = class Spell toString: -> "" + + shouldUseTranspiledCode: -> + # Determine whether this code has already been transpiled, or whether it's raw source needing transpilation. + return false unless @permissions.readwrite.length # Only player-writable code will be stored transpiled. + return true if @spectateView # Use transpiled code for both teams if we're just spectating. + teamSpells = @session.get('teamSpells') + team = @session.get('team') ? 'humans' + return true if teamSpells and not _.contains(teamSpells[team], @spellKey) # Use transpiled for enemy spells. + # 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')) + false diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee index 9933033d0..3c69d79c2 100644 --- a/app/views/play/level/tome/spell_view.coffee +++ b/app/views/play/level/tome/spell_view.coffee @@ -619,8 +619,11 @@ module.exports = class SpellView extends View @ace.setKeyboardHandler @keyBindings[aceConfig.keyBindings ? 'default'] onChangeLanguage: (e) -> - if @spell.canWrite() - @aceSession.setMode @editModes[e.language] + return unless @spell.canWrite() + @aceSession.setMode @editModes[e.language] + wasDefault = @getSource() is @spell.originalSource + @spell.setLanguage e.language + @reloadCode true if wasDefault dismiss: -> @spell.hasChangedSignificantly @getSource(), null, (hasChanged) => From d651885524e1b0bc22825148b8a6a6293c85212c Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Tue, 17 Jun 2014 16:40:12 -0400 Subject: [PATCH 7/9] Maybe fixing the toggleModal system once and for all. --- app/views/kinds/CocoView.coffee | 7 +------ .../views/editor/level/EditorLevelView.spec.coffee | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 test/app/views/editor/level/EditorLevelView.spec.coffee diff --git a/app/views/kinds/CocoView.coffee b/app/views/kinds/CocoView.coffee index 616fd7847..22e00f40e 100644 --- a/app/views/kinds/CocoView.coffee +++ b/app/views/kinds/CocoView.coffee @@ -150,12 +150,6 @@ module.exports = class CocoView extends Backbone.View @lastToggleModalCall = 0 toggleModal: (e) -> - if new Date().getTime() - CocoView.lastToggleModalCall < 5 - # Defensive move. This function has had a history of messing things up. - console.error 'toggleModal is getting called too often!' - return - CocoView.lastToggleModalCall = new Date().getTime() - if $(e.currentTarget).prop('target') is '_blank' return true # special handler for opening modals that are dynamically loaded, rather than static in the page. It works (or should work) like Bootstrap's modals, except use coco-modal for the data-toggle value. @@ -163,6 +157,7 @@ module.exports = class CocoView extends Backbone.View return unless elem.data('toggle') is 'coco-modal' target = elem.data('target') view = application.router.getView(target, '_modal') # could set up a system for loading cached modals, if told to + e.stopPropagation() @openModalView(view) openModalView: (modalView, softly=false) -> diff --git a/test/app/views/editor/level/EditorLevelView.spec.coffee b/test/app/views/editor/level/EditorLevelView.spec.coffee new file mode 100644 index 000000000..860fa826c --- /dev/null +++ b/test/app/views/editor/level/EditorLevelView.spec.coffee @@ -0,0 +1,14 @@ +EditorLevelView = require 'views/editor/level/edit' + +emptyLevel = {"_id":"53a0a1e2d9048dbc3a793c81","name":"Emptiness","description":"Tis nothing..","documentation":{"generalArticles":[],"specificArticles":[]},"scripts":[],"thangs":[],"systems":[],"victory":{},"version":{"minor":0,"major":0,"isLatestMajor":true,"isLatestMinor":true},"index":"5388f9ac9a904d0000d94f87","slug":"emptiness","creator":"5388f9ac9a904d0000d94f87","original":"53a0a1e2d9048dbc3a793c81","watchers":["5388f9ac9a904d0000d94f87"],"__v":0,"created":"2014-06-17T20:15:30.207Z","permissions":[{"access":"owner","target":"5388f9ac9a904d0000d94f87"}]} + +describe 'EditorLevelView', -> + describe 'revert button', -> + it 'opens just one modal when you click it', -> + view = new EditorLevelView({}, 'something') + request = jasmine.Ajax.requests.first() + request.response {status:200, responseText: JSON.stringify(emptyLevel)} + view.render() + spyOn(view, 'openModalView') + view.$el.find('#revert-button').click() + expect(view.openModalView.calls.count()).toBe(1) \ No newline at end of file From 50fea7e937e24ec69c3b5425b570472899bced04 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Tue, 17 Jun 2014 16:40:34 -0400 Subject: [PATCH 8/9] Added a method for returning all requests in mock-ajax. --- app/assets/javascripts/mock-ajax.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/javascripts/mock-ajax.js b/app/assets/javascripts/mock-ajax.js index d622aad13..966033263 100644 --- a/app/assets/javascripts/mock-ajax.js +++ b/app/assets/javascripts/mock-ajax.js @@ -235,6 +235,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. this.at = function(index) { return requests[index]; }; + + this.all = function() { + return requests.slice(0); + }; this.filter = function(url_to_match) { if (requests.length == 0) return []; From ac6c7292c895c7aaf27e9a4801bb5290512ef457 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Wed, 18 Jun 2014 12:05:40 -0700 Subject: [PATCH 9/9] Fixed Gridmancer session linking on profile view. --- app/views/account/profile_view.coffee | 2 +- app/views/modal/model_modal.coffee | 5 +---- server/users/user_handler.coffee | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/views/account/profile_view.coffee b/app/views/account/profile_view.coffee index e67b7a8fb..6f91cb5a6 100644 --- a/app/views/account/profile_view.coffee +++ b/app/views/account/profile_view.coffee @@ -254,7 +254,7 @@ module.exports = class ProfileView extends View link.icon = @iconForLink link for link in links context.profileLinks = _.sortBy links, (link) -> not link.icon # icons first if @sessions - context.sessions = (s.attributes for s in @sessions.models when (s.get('submitted') or s.get('level-id') is 'gridmancer')) + context.sessions = (s.attributes for s in @sessions.models when (s.get('submitted') or (s.get('levelID') is 'gridmancer') and s.get('code')?.thoktar?.plan?.length isnt 942)) # no default code context.sessions.sort (a, b) -> (b.playtime ? 0) - (a.playtime ? 0) else context.sessions = [] diff --git a/app/views/modal/model_modal.coffee b/app/views/modal/model_modal.coffee index 7424d6822..52c18b78d 100644 --- a/app/views/modal/model_modal.coffee +++ b/app/views/modal/model_modal.coffee @@ -54,18 +54,15 @@ module.exports = class ModelModal extends View container = $(e.target).closest('.model-container') model = _.find @models, id: container.data('model-id') treema = @modelTreemas[model.id] - changes = {} for key, val of treema.data when not _.isEqual val, model.get key console.log "Updating", key, "from", model.get(key), "to", val model.set key, val - changes[key] = val for key, val of model.attributes when treema.get(key) is undefined and not _.string.startsWith key, '_' console.log "Deleting", key, "which was", val, "but man, that ain't going to work, now is it?" - #changes[key] = undefined model.unset key if errors = model.validate() return console.warn model, "failed validation with errors:", errors - res = model.save changes, {patch: true} + return unless res = model.patch() res.error => return if @destroyed console.error model, "failed to save with error:", res.responseText diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index af797f614..6d4609d35 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -229,7 +229,7 @@ UserHandler = class UserHandler extends Handler getLevelSessionsForEmployer: (req, res, userID) -> 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']} - projection = 'levelName levelID team playtime codeLanguage submitted' # code totalScore + projection = 'levelName levelID team playtime codeLanguage submitted code totalScore' LevelSession.find(query).select(projection).exec (err, documents) => return @sendDatabaseError(res, err) if err documents = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)