Skip to content

Commit

Permalink
Merge branch 'master' into concept-tagging
Browse files Browse the repository at this point in the history
  • Loading branch information
sderickson committed Jan 17, 2018
2 parents 2152996 + 37aa4e9 commit bb0fbdf
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 107 deletions.
45 changes: 1 addition & 44 deletions app/lib/LevelSetupManager.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,7 @@ module.exports = class LevelSetupManager extends CocoClass
@session.set 'heroConfig', {"thangType":sorcerer,"inventory":{"misc-0":"53e2396a53457600003e3f0f","programming-book":"546e266e9df4a17d0d449be5","minion":"54eb5dbc49fa2d5c905ddf56","feet":"53e214f153457600003e3eab","right-hand":"54eab7f52b7506e891ca7202","left-hand":"5463758f3839c6e02811d30f","wrists":"54693797a2b1f53ce79443e9","gloves":"5469425ca2b1f53ce7944421","torso":"546d4a549df4a17d0d449a97","neck":"54693274a2b1f53ce79443c9","eyes":"546941fda2b1f53ce794441d","head":"546d4ca19df4a17d0d449abf"}}
@onInventoryModalPlayClicked()
return

if @level.get('slug') is 'escort-duty'
potionmaster = '52e9adf7427172ae56002172'
@session.set 'heroConfig', {"thangType":potionmaster,"inventory":{
"eyes": "546941fda2b1f53ce794441d",
"feet": "546d4d8e9df4a17d0d449acd",
"programming-book": "557871261ff17fef5abee3ee",
"head": "546d4ca19df4a17d0d449abf",
"torso": "546d4a549df4a17d0d449a97",
"left-ring": "5441c35c4e9aeb727cc9711d",
"minion": "54eb5d1649fa2d5c905ddf52",
"neck": "54693363a2b1f53ce79443d1",
"wrists": "54693830a2b1f53ce79443f1",
"left-hand": "546376ea3839c6e02811d320",
"right-hand": "54eab92b2b7506e891ca720a",
"waist": "54694af7a2b1f53ce7944441",
"right-ring": "54692d2aa2b1f53ce794438f"
}}
@onInventoryModalPlayClicked()
return

if @level.get('slug') in ['ace-of-coders', 'elemental-wars']
if @level.get('slug') is 'ace-of-coders'
goliath = '55e1a6e876cb0948c96af9f8'
@session.set 'heroConfig', {"thangType":goliath,"inventory":{"eyes":"53eb99f41a100989a40ce46e","neck":"54693274a2b1f53ce79443c9","wrists":"54693797a2b1f53ce79443e9","feet":"546d4d8e9df4a17d0d449acd","minion":"54eb5bf649fa2d5c905ddf4a","programming-book":"557871261ff17fef5abee3ee"}}
@onInventoryModalPlayClicked()
Expand All @@ -113,28 +92,6 @@ module.exports = class LevelSetupManager extends CocoClass
"left-ring": "54692d2aa2b1f53ce794438f"
}
}

if @level.get('slug') is 'tesla-tesoro'
assassin = '566a2202e132c81f00f38c81'
@session.set 'heroConfig', {
"thangType": assassin
"inventory":{
"eyes": "546941fda2b1f53ce794441d",
"feet": "546d4d8e9df4a17d0d449acd",
"minion": "54eb5d1649fa2d5c905ddf52",
"neck": "54693363a2b1f53ce79443d1",
"wrists": "54693830a2b1f53ce79443f1",
"programming-book": "557871261ff17fef5abee3ee",
"left-ring": "5441c35c4e9aeb727cc9711d",
"torso": "546d3d549df4a17d0d449a47",
"head": "546d47c09df4a17d0d449a6f",
"left-hand": "54eb528449fa2d5c905ddf12",
"right-hand": "544d86318494308424f564e8"
}
}
@onInventoryModalPlayClicked()
return

if @level.get('slug') is 'assembly-speed'
raider = '55527eb0b8abf4ba1fe9a107'
@session.set 'heroConfig', {"thangType":raider,"inventory":{}}
Expand Down
2 changes: 1 addition & 1 deletion app/locale/cs.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr
fork_title: "Forkovat novou verzi"
fork_creating: "Vytváření Forku..."
generate_terrain: "Generování terénu"
more: "Vícee"
more: "Více"
wiki: "Wiki"
live_chat: "Živý Chat"
thang_main: "Hlavní"
Expand Down
2 changes: 1 addition & 1 deletion app/schemas/models/level.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ _.extend LevelSchema.properties,
buildTime: {type: 'number', description: 'How long it has taken to build this level.'}
practice: { type: 'boolean' }
practiceThresholdMinutes: {type: 'number', description: 'Players with larger playtimes may be directed to a practice level.'}
assessment: { type: 'boolean', description: 'Set to true if this is an assessment level.' }
assessment: { type: ['boolean', 'string'], enum: [true, false, 'open-ended'], description: 'Set to true if this is an assessment level.' }
primerLanguage: { type: 'string', enum: ['javascript', 'python'], description: 'Programming language taught by this level.' }
shareable: { title: 'Shareable', type: ['string', 'boolean'], enum: [false, true, 'project'], description: 'Whether the level is not shareable (false), shareable (true), or a sharing-encouraged project level ("project"). Make sure to use "project" for project levels so they show up correctly in the Teacher Dashboard.' }

Expand Down
2 changes: 2 additions & 0 deletions app/schemas/subscriptions/play.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,5 @@ module.exports =
'level:contact-button-pressed': c.object {title: 'Contact Pressed', description: 'Dispatched when the contact button is pressed in a level.'}

'level:license-required': c.object {}

'level:open-items-modal': c.object {}
4 changes: 2 additions & 2 deletions app/views/play/common/LadderSubmissionView.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ module.exports = class LadderSubmissionView extends CocoView
data: ajaxData
success: success
error: failure
if @mirrorSession and @mirrorSession.get('submittedCode')
if @mirrorSession
# Also submit the mirrorSession after the main session submits successfully.
mirrorAjaxData = _.clone ajaxData
mirrorAjaxData.session = @mirrorSession.id
mirrorCode = @mirrorSession.get('code')
mirrorCode = @mirrorSession.get('code') ? {}
if @session.get('team') is 'humans'
mirrorCode['hero-placeholder-1'] = @session.get('code')['hero-placeholder']
else
Expand Down
5 changes: 4 additions & 1 deletion app/views/play/level/LevelDialogueView.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ require('app/styles/play/level/level-dialogue-view.sass')
CocoView = require 'views/core/CocoView'
template = require 'templates/play/level/level-dialogue-view'
DialogueAnimator = require './DialogueAnimator'
PlayItemsModal = require 'views/play/modal/PlayItemsModal'

module.exports = class LevelDialogueView extends CocoView
id: 'level-dialogue-view'
Expand All @@ -13,6 +14,7 @@ module.exports = class LevelDialogueView extends CocoView
'level:shift-space-pressed': 'onShiftSpacePressed'
'level:escape-pressed': 'onEscapePressed'
'sprite:dialogue-sound-completed': 'onDialogueSoundCompleted'
'level:open-items-modal': 'openItemsModal'

events:
'click': 'onClick'
Expand All @@ -29,10 +31,11 @@ module.exports = class LevelDialogueView extends CocoView
onClickLink: (e) ->
route = $(e.target).attr('href')
if route and /item-store/.test route
PlayItemsModal = require 'views/play/modal/PlayItemsModal'
@openModalView new PlayItemsModal supermodel: @supermodal
e.stopPropagation()

openItemsModal: (e) ->
@openModalView new PlayItemsModal supermodel: @supermodal

onSpriteDialogue: (e) ->
return unless e.message
Expand Down
41 changes: 4 additions & 37 deletions app/views/play/level/PlayLevelView.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -366,46 +366,11 @@ module.exports = class PlayLevelView extends RootView
if e.session.get('creator') is '532dbc73a622924444b68ed9' # Wizard Dude gets his own avatar
sorcerer = '53e126a4e06b897606d38bef'
e.session.set 'heroConfig', {"thangType":sorcerer,"inventory":{"misc-0":"53e2396a53457600003e3f0f","programming-book":"546e266e9df4a17d0d449be5","minion":"54eb5dbc49fa2d5c905ddf56","feet":"53e214f153457600003e3eab","right-hand":"54eab7f52b7506e891ca7202","left-hand":"5463758f3839c6e02811d30f","wrists":"54693797a2b1f53ce79443e9","gloves":"5469425ca2b1f53ce7944421","torso":"546d4a549df4a17d0d449a97","neck":"54693274a2b1f53ce79443c9","eyes":"546941fda2b1f53ce794441d","head":"546d4ca19df4a17d0d449abf"}}
else if e.level.get('slug') in ['ace-of-coders', 'elemental-wars']
else if e.level.get('slug') is 'ace-of-coders'
goliath = '55e1a6e876cb0948c96af9f8'
e.session.set 'heroConfig', {"thangType":goliath,"inventory":{
"eyes":"53eb99f41a100989a40ce46e","neck":"54693274a2b1f53ce79443c9","wrists":"54693797a2b1f53ce79443e9","feet":"546d4d8e9df4a17d0d449acd","minion":"54eb5bf649fa2d5c905ddf4a","programming-book":"557871261ff17fef5abee3ee"
}}
else if e.level.get('slug') in ['tesla-tesoro']
assassin = '566a2202e132c81f00f38c81'
e.session.set 'heroConfig', {"thangType":assassin,"inventory":{
"eyes": "546941fda2b1f53ce794441d",
"feet": "546d4d8e9df4a17d0d449acd",
"minion": "54eb5d1649fa2d5c905ddf52",
"neck": "54693363a2b1f53ce79443d1",
"wrists": "54693830a2b1f53ce79443f1",
"programming-book": "557871261ff17fef5abee3ee",
"left-ring": "5441c35c4e9aeb727cc9711d",
"torso": "546d3d549df4a17d0d449a47",
"head": "546d47c09df4a17d0d449a6f",
"left-hand": "54eb528449fa2d5c905ddf12",
"right-hand": "544d86318494308424f564e8"
}}
else if e.level.get('slug') in ['escort-duty']
potionmaster = '52e9adf7427172ae56002172'
e.session.set 'heroConfig', {"thangType":potionmaster,"inventory":{
"eyes": "546941fda2b1f53ce794441d",
"feet": "546d4d8e9df4a17d0d449acd",
"programming-book": "557871261ff17fef5abee3ee",
"head": "546d4ca19df4a17d0d449abf",
"torso": "546d4a549df4a17d0d449a97",
"left-ring": "5441c35c4e9aeb727cc9711d",
"minion": "54eb5d1649fa2d5c905ddf52",
"neck": "54693363a2b1f53ce79443d1",
"wrists": "54693830a2b1f53ce79443f1",
"left-hand": "546376ea3839c6e02811d320",
"right-hand": "54eab92b2b7506e891ca720a",
"waist": "54694af7a2b1f53ce7944441",
"right-ring": "54692d2aa2b1f53ce794438f"
}}



else if e.level.get('slug') is 'the-battle-of-sky-span'
wizard = '52fc1460b2b91c0d5a7b6af3'
e.session.set 'heroConfig', {"thangType":wizard,"inventory":{}}
Expand Down Expand Up @@ -563,7 +528,9 @@ module.exports = class PlayLevelView extends RootView

shouldSimulate: ->
return true if utils.getQueryVariable('simulate') is true
return false # Disabled due to unresolved crashing issues
return false if utils.getQueryVariable('simulate') is false
return false if @isEditorPreview
defaultCores = 2
cores = window.navigator.hardwareConcurrency or defaultCores # Available on Chrome/Opera, soon Safari
defaultHeapLimit = 793000000
Expand All @@ -574,7 +541,7 @@ module.exports = class PlayLevelView extends RootView
return false if $.browser?.msie or $.browser?.msedge
return false if $.browser.linux
return false if me.level() < 8
return false if @level.get('slug') in ['zero-sum', 'ace-of-coders']
return false if @level.get('slug') in ['zero-sum', 'ace-of-coders', 'elemental-wars']
if @level.isType('course', 'game-dev', 'web-dev')
return false
else if @level.isType('hero') and gamesSimulated
Expand Down
4 changes: 4 additions & 0 deletions app/views/play/level/tome/CastButtonView.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module.exports = class CastButtonView extends CocoView
@observing = options.session.get('creator') isnt me.id
# WARNING: CourseVictoryModal does not handle mirror sessions when submitting to ladder; adjust logic if a
# mirror level is added to
# Keep server/middleware/levels.coffee mirror list in sync with this one
@loadMirrorSession() if @options.level.get('slug') in ['ace-of-coders', 'elemental-wars', 'the-battle-of-sky-span', 'tesla-tesoro', 'escort-duty']
@mirror = @mirrorSession?
@autoSubmitsToLadder = @options.level.isType('course-ladder')
Expand Down Expand Up @@ -174,10 +175,13 @@ module.exports = class CastButtonView extends CocoView
submitAgainLabel.text waitTime

loadMirrorSession: ->
# Future work would be to only load this the first time we are going to submit (or auto submit), so that if we write some code but don't submit it, the other session can still initialize itself with it.
url = "/db/level/#{@options.level.get('slug') or @options.level.id}/session"
url += "?team=#{if me.team is 'humans' then 'ogres' else 'humans'}"
mirrorSession = new LevelSession().setURL url
@mirrorSession = @supermodel.loadModel(mirrorSession, {cache: false}).model
@listenToOnce @mirrorSession, 'sync', ->
@ladderSubmissionView?.mirrorSession = @mirrorSession

updateLadderSubmissionViews: ->
@removeSubView subview for key, subview of @subviews when subview instanceof LadderSubmissionView
Expand Down
41 changes: 27 additions & 14 deletions scripts/mongodb/translation-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
// * return after the first change is found (commented out)
// * uncomment "return true" lines

// TODO: update to import Article translations

// Constants (change these for different languages)
langCode = 'zh-HANS';
langProperty = 'Chinese'; // Match column name in CSV
fileName = 'common-zh-HANS.csv';
langCode = 'he';
langProperty = 'Hebrew'; // Match column name in CSV
fileName = 'en-to-he-2017-12-22.csv';
doSave = false; // Change to true to actually save

if (!doSave)
Expand Down Expand Up @@ -85,17 +83,24 @@ update = _.curry(function(translationMap, propertyPrefix, rootDoc, property) {
if (!rootDoc.i18n) { rootDoc.i18n = {} }
if (!rootDoc.i18n[langCode]) { rootDoc.i18n[langCode] = {} }
var oldTranslation = rootDoc.i18n[langCode][property];
logUpdate(englishString, translation, oldTranslation);
rootDoc.i18n[langCode][property] = translation
if(logUpdate(englishString, translation, oldTranslation))
rootDoc.i18n[langCode][property] = translation
})

function logUpdate(englishString, translation, oldTranslation) {
if (langCode == 'he' && oldTranslation && isHebrew(oldTranslation) && translation != oldTranslation) {
console.log("Skipping overwriting on", englishString);
++unchangedCount;
return false; // Don't overwrite any Hebrew, it might be a more recent correction from proofreader
}
if (translation != oldTranslation) {
++updatedCount;
console.log('Changed:',updatedCount,'\tUpdating translation\nFor:', englishString.slice(0,100).replace(/\n/g, '\\n'), '\nOld:', (oldTranslation || '').slice(0,100).replace(/\n/g, '\\n'), '\nNew:', translation.slice(0,100).replace(/\n/g, '\\n'),'\n');
return true;
}
else {
++unchangedCount;
return true;
}
}

Expand All @@ -122,7 +127,7 @@ function normalizeEscapesAndPunctuationValues(s) {
s = s.replace(/\\r/g, '');
s = s.replace(/\\n/g, '\n');
s = s.replace(/\\"/g, '"');
if (langCode == 'zh-HANS') {
if (langCode == 'zh-HANS' || langCode == 'he') {
var s1 = s;
s = s.replace(/\\/, '"'); // Saw this in Chinese spreadsheet import once, probably don't want to use generally unless problem resurfaces
if (s != s1) {
Expand Down Expand Up @@ -228,8 +233,8 @@ co(function* () {
if (!method.i18n) { method.i18n = {} }
if (!method.i18n[langCode]) { method.i18n[langCode] = {} }
if (!method.i18n[langCode].context) { method.i18n[langCode].context = {} }
logUpdate(englishString, translationMap[normalizedEnglish], method.i18n[langCode].context[property]);
method.i18n[langCode].context[property] = translationMap[normalizedEnglish]
if(logUpdate(englishString, translationMap[normalizedEnglish], method.i18n[langCode].context[property]))
method.i18n[langCode].context[property] = translationMap[normalizedEnglish]
})
})
}
Expand Down Expand Up @@ -353,8 +358,12 @@ co(function* () {
if (!propDoc.i18n) { return }
if (!propDoc.i18n[langCode]) { propDoc.i18n[langCode] = {} }
if (!propDoc.i18n[langCode].description) { propDoc.i18n[langCode].description = {} }
logUpdate(englishString, translationMap[normalizedEnglish], propDoc.i18n[langCode].description[j]);
propDoc.i18n[langCode].description[j] = translationMap[normalizedEnglish]
if (langCode == 'he' && translationMap[normalizedEnglish] && isHebrew(translationMap[normalizedEnglish])) {
console.log("Skipping overwriting on", englishString);
return; // Don't overwrite any Hebrew, it might be a more recent correction from proofreader
}
if(logUpdate(englishString, translationMap[normalizedEnglish], propDoc.i18n[langCode].description[j]))
propDoc.i18n[langCode].description[j] = translationMap[normalizedEnglish]
})
}
_.forEach(propDoc.context, function(value, j) {
Expand All @@ -364,8 +373,12 @@ co(function* () {
if (!propDoc.i18n) { return }
if (!propDoc.i18n[langCode]) { propDoc.i18n[langCode] = {} }
if (!propDoc.i18n[langCode].context) { propDoc.i18n[langCode].context = {} }
logUpdate(englishString, translationMap[normalizedEnglish], propDoc.i18n[langCode].context[j]);
propDoc.i18n[langCode].context[j] = translationMap[normalizedEnglish]
if (langCode == 'he' && translationMap[normalizedEnglish] && isHebrew(translationMap[normalizedEnglish])) {
console.log("Skipping overwriting on", englishString);
return; // Don't overwrite any Hebrew, it might be a more recent correction from proofreader
}
if(logUpdate(englishString, translationMap[normalizedEnglish], propDoc.i18n[langCode].context[j]))
propDoc.i18n[langCode].context[j] = translationMap[normalizedEnglish]
})
})

Expand Down
23 changes: 19 additions & 4 deletions server/middleware/levels.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ log = require 'winston'

module.exports =
upsertSession: wrap (req, res) ->
level = yield database.getDocFromHandle(req, Level)
level = yield database.getDocFromHandle(req, Level) # TODO: project only fields we need?
if not level
throw new errors.NotFound('Level not found.')
levelOriginal = level.get('original')
Expand Down Expand Up @@ -58,6 +58,17 @@ module.exports =
if session
return res.send(session.toObject({req: req}))

mirrorMatches = ['ace-of-coders', 'elemental-wars', 'the-battle-of-sky-span', 'tesla-tesoro', 'escort-duty']
if sessionQuery.team and level.get('slug') in mirrorMatches
# Find their other session for this, so that if it exists, we can initialize the new team's session with the mirror code.
otherTeam = if sessionQuery.team is 'humans' then 'ogres' else 'humans'
otherSessionQuery = _.defaults {team: otherTeam, code: {$exists: true}}, sessionQuery
otherSession = yield LevelSession.findOne(otherSessionQuery).select('team code codeLanguage')
if otherSession
heroSlugs = humans: 'hero-placeholder', ogres: 'hero-placeholder-1'
code = {}
code[heroSlugs[sessionQuery.team]] = plan: otherSession.get('code')[heroSlugs[otherSession.get('team')]].plan

attrs = sessionQuery
_.extend(attrs, {
state:
Expand All @@ -68,10 +79,14 @@ module.exports =
{target: req.user.id, access: 'owner'}
{target: 'public', access: 'write'}
]
codeLanguage: req.user.get('aceConfig')?.language ? 'python'
codeLanguage: otherSession?.get('codeLanguage') ? req.user.get('aceConfig')?.language ? 'python'
})
if code
attrs.code = code

if level.get('type') in ['course', 'course-ladder'] or req.query.course?
if req.user.isAdmin()
null # Admins can play any level, even if it's not in a course yet (example: level editor)
else if level.get('type') in ['course', 'course-ladder'] or req.query.course?

# Find the course and classroom that has assigned this level, verify access
# Handle either being given the courseInstance, or having to deduce it
Expand Down Expand Up @@ -131,7 +146,7 @@ module.exports =
query = {
_id: mongoose.Types.ObjectId(req.query.campaign),
type: 'hoc'
"levels.#{level.get('original')}": {$exists: true}
"levels.#{level.get('original')}": {$exists: true}
}
campaign = yield Campaign.count(query)
if campaign
Expand Down
2 changes: 1 addition & 1 deletion server/models/Classroom.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ ClassroomSchema.methods.fetchSessionsForMembers = co.wrap (members) ->
memberCoursesMap[userID.toHexString()] ?= []
memberCoursesMap[userID.toHexString()].push(courseInstance.courseID)
dbqs = []
select = 'state.complete level creator playtime changed created dateFirstCompleted submitted published'
select = 'state.complete level creator playtime changed created dateFirstCompleted submitted published code'
$or = []
for member in members
for courseID in memberCoursesMap[member.toHexString()] ? []
Expand Down

0 comments on commit bb0fbdf

Please sign in to comment.