mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-29 18:45:48 -05:00
commit
22b7e52f98
19 changed files with 88 additions and 25 deletions
|
@ -1,8 +1,8 @@
|
||||||
module.exports = initializeGoogle = ->
|
module.exports = initializeGoogle = ->
|
||||||
onGPlusLoaded = ->
|
window.onGPlusLoaded = ->
|
||||||
Backbone.Mediator.publish "gapi-loaded"
|
Backbone.Mediator.publish "gapi-loaded"
|
||||||
return
|
return
|
||||||
signinCallback = (authResult) ->
|
window.signinCallback = (authResult) ->
|
||||||
Backbone.Mediator.publish "gplus-logged-in", authResult if authResult["access_token"]
|
Backbone.Mediator.publish "gplus-logged-in", authResult if authResult["access_token"]
|
||||||
return
|
return
|
||||||
(->
|
(->
|
||||||
|
|
|
@ -288,10 +288,13 @@ module.exports = class Camera extends CocoClass
|
||||||
boundTarget: (pos, zoom) ->
|
boundTarget: (pos, zoom) ->
|
||||||
# Given an {x, y} in Surface coordinates, return one that will keep our viewport on the Surface.
|
# Given an {x, y} in Surface coordinates, return one that will keep our viewport on the Surface.
|
||||||
return pos unless @bounds
|
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)
|
marginX = (@canvasWidth / zoom / 2)
|
||||||
marginY = (@canvasHeight / zoom / 2)
|
marginY = (@canvasHeight / zoom / 2)
|
||||||
x = Math.min(Math.max(marginX + @bounds.x, pos.x + @offset.x), @bounds.x + @bounds.width - marginX)
|
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}
|
{x: x, y: y}
|
||||||
|
|
||||||
updateViewports: (target) ->
|
updateViewports: (target) ->
|
||||||
|
|
|
@ -207,7 +207,10 @@ class CocoModel extends Backbone.Model
|
||||||
|
|
||||||
applyDelta: (delta) ->
|
applyDelta: (delta) ->
|
||||||
newAttributes = $.extend(true, {}, @attributes)
|
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
|
@set newAttributes
|
||||||
|
|
||||||
getExpandedDelta: ->
|
getExpandedDelta: ->
|
||||||
|
|
|
@ -122,7 +122,7 @@ module.exports = class SuperModel extends Backbone.Model
|
||||||
return @progress is 1.0 or not @denom
|
return @progress is 1.0 or not @denom
|
||||||
|
|
||||||
addModelResource: (modelOrCollection, name, fetchOptions, value=1) ->
|
addModelResource: (modelOrCollection, name, fetchOptions, value=1) ->
|
||||||
modelOrCollection.saveBackups = @shouldSaveBackups(modelOrCollection)
|
modelOrCollection.saveBackups = modelOrCollection.saveBackups or @shouldSaveBackups(modelOrCollection)
|
||||||
@checkName(name)
|
@checkName(name)
|
||||||
res = new ModelResource(modelOrCollection, name, fetchOptions, value)
|
res = new ModelResource(modelOrCollection, name, fetchOptions, value)
|
||||||
@storeResource(res, value)
|
@storeResource(res, value)
|
||||||
|
|
|
@ -49,6 +49,9 @@
|
||||||
tr
|
tr
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
|
tr.expired
|
||||||
|
opacity: 0.5
|
||||||
|
|
||||||
code
|
code
|
||||||
background-color: rgb(220, 220, 220)
|
background-color: rgb(220, 220, 220)
|
||||||
color: #555
|
color: #555
|
||||||
|
|
|
@ -1,5 +1,21 @@
|
||||||
#docs-modal .modal-dialog
|
#docs-modal .modal-dialog
|
||||||
width: 800px
|
width: 800px
|
||||||
|
|
||||||
|
.tab-content
|
||||||
|
padding-top: 20px
|
||||||
|
|
||||||
li:not(.active) a[data-toggle="tab"]
|
li:not(.active) a[data-toggle="tab"]
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
|
img
|
||||||
|
display: block
|
||||||
|
margin: 0 auto
|
||||||
|
|
||||||
|
em
|
||||||
|
display: block
|
||||||
|
margin: 0 auto
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
hr
|
||||||
|
border-color: #5c5c5c
|
||||||
|
width: 80%
|
|
@ -93,7 +93,9 @@ block content
|
||||||
for candidate, index in area.candidates
|
for candidate, index in area.candidates
|
||||||
- var profile = candidate.get('jobProfile');
|
- var profile = candidate.get('jobProfile');
|
||||||
- var authorized = candidate.id; // If we have the id, then we are authorized.
|
- 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
|
td
|
||||||
if authorized
|
if authorized
|
||||||
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=50)
|
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=50)
|
||||||
|
@ -115,7 +117,7 @@ block content
|
||||||
code= skill
|
code= skill
|
||||||
span
|
span
|
||||||
td= profile.experience
|
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()
|
if me.isAdmin()
|
||||||
td= remarks[candidate.id] ? remarks[candidate.id].get('contactName') : ''
|
td= remarks[candidate.id] ? remarks[candidate.id].get('contactName') : ''
|
||||||
if me.isAdmin() && area.id == 'inactive-candidates'
|
if me.isAdmin() && area.id == 'inactive-candidates'
|
||||||
|
|
|
@ -22,7 +22,11 @@ block content
|
||||||
p
|
p
|
||||||
strong Tournament ended!
|
strong Tournament ended!
|
||||||
a(href="#winners") Behold the winners
|
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
|
p
|
||||||
| Want to commiserate? Head over to
|
| Want to commiserate? Head over to
|
||||||
a(href="http://discourse.codecombat.com/") the forum
|
a(href="http://discourse.codecombat.com/") the forum
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ul#primary-goals-list
|
ul#primary-goals-list
|
||||||
div.goals-status
|
div.goals-status
|
||||||
strong(data-i18n="play_level.goals") Goals
|
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.success").secret.goal-status.success Success!
|
||||||
span(data-i18n="play_level.incomplete").secret.goal-status.incomplete Incomplete
|
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
|
span(data-i18n="play_level.timed_out").secret.goal-status.timed-out Ran out of time
|
||||||
|
|
|
@ -22,6 +22,7 @@ adminContacts = [
|
||||||
{id: "5162fab9c92b4c751e000274", name: "Scott"}
|
{id: "5162fab9c92b4c751e000274", name: "Scott"}
|
||||||
{id: "51eb2714fa058cb20d0006ef", name: "Michael"}
|
{id: "51eb2714fa058cb20d0006ef", name: "Michael"}
|
||||||
{id: "51538fdb812dd9af02000001", name: "George"}
|
{id: "51538fdb812dd9af02000001", name: "George"}
|
||||||
|
{id: "52a57252a89409700d0000d9", name: "Ignore"}
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = class ProfileView extends View
|
module.exports = class ProfileView extends View
|
||||||
|
@ -104,6 +105,7 @@ module.exports = class ProfileView extends View
|
||||||
@linkedinLoaded = true
|
@linkedinLoaded = true
|
||||||
if @waitingForLinkedIn
|
if @waitingForLinkedIn
|
||||||
@renderLinkedInButton()
|
@renderLinkedInButton()
|
||||||
|
@authorizedWithLinkedIn = IN?.User?.isAuthorized()
|
||||||
|
|
||||||
renderLinkedInButton: =>
|
renderLinkedInButton: =>
|
||||||
IN?.parse()
|
IN?.parse()
|
||||||
|
|
|
@ -101,6 +101,7 @@ module.exports = class ArticleEditView extends View
|
||||||
@disableModalInProgress(modal)
|
@disableModalInProgress(modal)
|
||||||
|
|
||||||
res.success =>
|
res.success =>
|
||||||
|
@article.clearBackup()
|
||||||
modal.modal('hide')
|
modal.modal('hide')
|
||||||
url = "/editor/article/#{newArticle.get('slug') or newArticle.id}"
|
url = "/editor/article/#{newArticle.get('slug') or newArticle.id}"
|
||||||
document.location.href = url
|
document.location.href = url
|
||||||
|
|
|
@ -96,6 +96,8 @@ module.exports = class LevelSaveView extends SaveVersionModal
|
||||||
forms.applyErrorsToForm($(form), JSON.parse(res.responseText))
|
forms.applyErrorsToForm($(form), JSON.parse(res.responseText))
|
||||||
res.success =>
|
res.success =>
|
||||||
modelsToSave = _.without modelsToSave, newModel
|
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
|
unless modelsToSave.length
|
||||||
url = "/editor/level/#{@level.get('slug') or @level.id}"
|
url = "/editor/level/#{@level.get('slug') or @level.id}"
|
||||||
document.location.href = url
|
document.location.href = url
|
||||||
|
|
|
@ -326,7 +326,9 @@ module.exports = class ThangTypeEditView extends View
|
||||||
image = @currentSprite.imageObject.image
|
image = @currentSprite.imageObject.image
|
||||||
portraitSource = imageToPortrait image
|
portraitSource = imageToPortrait image
|
||||||
# bit of a hacky way to get that portrait
|
# 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
|
newThangType.uploadGenericPortrait success, portraitSource
|
||||||
|
|
||||||
clearRawData: ->
|
clearRawData: ->
|
||||||
|
|
|
@ -14,9 +14,9 @@ module.exports = class GoldView extends View
|
||||||
super options
|
super options
|
||||||
@teamGold = {}
|
@teamGold = {}
|
||||||
@teamGoldEarned = {}
|
@teamGoldEarned = {}
|
||||||
|
@shownOnce = false
|
||||||
|
|
||||||
onGoldChanged: (e) ->
|
onGoldChanged: (e) ->
|
||||||
@$el.show()
|
|
||||||
return if @teamGold[e.team] is e.gold and @teamGoldEarned[e.team] is e.goldEarned
|
return if @teamGold[e.team] is e.gold and @teamGoldEarned[e.team] is e.goldEarned
|
||||||
@teamGold[e.team] = e.gold
|
@teamGold[e.team] = e.gold
|
||||||
@teamGoldEarned[e.team] = e.goldEarned
|
@teamGoldEarned[e.team] = e.goldEarned
|
||||||
|
@ -30,9 +30,11 @@ module.exports = class GoldView extends View
|
||||||
text += " (#{e.goldEarned})"
|
text += " (#{e.goldEarned})"
|
||||||
goldEl.text text
|
goldEl.text text
|
||||||
@updateTitle()
|
@updateTitle()
|
||||||
|
@$el.show()
|
||||||
|
@shownOnce = true
|
||||||
|
|
||||||
updateTitle: ->
|
updateTitle: ->
|
||||||
@$el.attr 'title', ("Team '#{team}' has #{gold} now of #{@teamGoldEarned[team]} gold earned." for team, gold of @teamGold).join ' '
|
@$el.attr 'title', ("Team '#{team}' has #{gold} now of #{@teamGoldEarned[team]} gold earned." for team, gold of @teamGold).join ' '
|
||||||
|
|
||||||
onSetLetterbox: (e) ->
|
onSetLetterbox: (e) ->
|
||||||
@$el.toggle not e.on
|
@$el.toggle not e.on if @shownOnce
|
||||||
|
|
|
@ -8,6 +8,7 @@ utils = require 'lib/utils'
|
||||||
module.exports = class DocsModal extends View
|
module.exports = class DocsModal extends View
|
||||||
template: template
|
template: template
|
||||||
id: 'docs-modal'
|
id: 'docs-modal'
|
||||||
|
plain: true
|
||||||
|
|
||||||
shortcuts:
|
shortcuts:
|
||||||
'enter': 'hide'
|
'enter': 'hide'
|
||||||
|
|
|
@ -180,7 +180,7 @@ module.exports = class SpellView extends View
|
||||||
return (owner is 'this' or owner is 'more') and (not doc.owner? or doc.owner is 'this')
|
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
|
console.log 'could not find doc for', prop, 'from', e.allDocs['__' + prop], 'for', owner, 'of', e.propGroups unless doc
|
||||||
doc ?= prop
|
doc ?= prop
|
||||||
if doc.snippets?
|
if doc.snippets?[@spell.language]
|
||||||
entry =
|
entry =
|
||||||
content: doc.snippets[@spell.language].code
|
content: doc.snippets[@spell.language].code
|
||||||
name: doc.name
|
name: doc.name
|
||||||
|
|
|
@ -3,6 +3,7 @@ fs = require 'fs'
|
||||||
request = require 'request'
|
request = require 'request'
|
||||||
mongoose = require('mongoose')
|
mongoose = require('mongoose')
|
||||||
errors = require '../commons/errors'
|
errors = require '../commons/errors'
|
||||||
|
config = require '../../server_config'
|
||||||
|
|
||||||
module.exports.setup = (app) ->
|
module.exports.setup = (app) ->
|
||||||
app.all '/file*', (req, res) ->
|
app.all '/file*', (req, res) ->
|
||||||
|
@ -130,6 +131,8 @@ checkExistence = (options, req, res, force, done) ->
|
||||||
errors.conflict(res, {canForce:userCanEditFile(req.user, file)})
|
errors.conflict(res, {canForce:userCanEditFile(req.user, file)})
|
||||||
done(true)
|
done(true)
|
||||||
else if file
|
else if file
|
||||||
|
fullPath = "/file/#{options.metadata.path}/#{options.filename}"
|
||||||
|
clearCloudFlareCacheForFile(fullPath)
|
||||||
q = { _id: file._id }
|
q = { _id: file._id }
|
||||||
q.root = 'media'
|
q.root = 'media'
|
||||||
Grid.gfs.remove q, (err) ->
|
Grid.gfs.remove q, (err) ->
|
||||||
|
@ -172,3 +175,20 @@ createPostOptions = (req) ->
|
||||||
options.metadata.description = req.body.description if req.body.description?
|
options.metadata.description = req.body.description if req.body.description?
|
||||||
|
|
||||||
options
|
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', config.cloudflare.token
|
||||||
|
form.append 'email', 'scott@codecombat.com'
|
||||||
|
form.append 'z', 'codecombat.com'
|
||||||
|
form.append 'a', 'zone_file_purge'
|
||||||
|
form.append 'url', "http://codecombat.com#{path}"
|
||||||
|
|
|
@ -308,9 +308,9 @@ UserHandler = class UserHandler extends Handler
|
||||||
|
|
||||||
getCandidates: (req, res) ->
|
getCandidates: (req, res) ->
|
||||||
authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
||||||
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 = {'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()
|
query['jobProfile.active'] = true unless req.user.isAdmin()
|
||||||
selection = 'jobProfile jobProfileApproved photoURL'
|
selection = 'jobProfile jobProfileApproved photoURL'
|
||||||
selection += ' email name' if authorized
|
selection += ' email name' if authorized
|
||||||
|
|
|
@ -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.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.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 =
|
config.mongo =
|
||||||
port: process.env.COCO_MONGO_PORT or 27017
|
port: process.env.COCO_MONGO_PORT or 27017
|
||||||
|
|
Loading…
Reference in a new issue