From b64bcd9f02b57c2bd082256be2520b5bfcdc2aaa Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Fri, 15 Jul 2016 23:26:43 -0700 Subject: [PATCH] Use shareable false/true/'project' for different levels of shareability --- app/models/Classroom.coffee | 2 +- app/schemas/models/campaign.schema.coffee | 1 + app/schemas/models/classroom.schema.coffee | 2 +- app/schemas/models/level.coffee | 2 +- app/styles/courses/teacher-class-view.sass | 3 +++ app/templates/courses/course-details.jade | 2 +- app/templates/play/level/tome/spell-top-bar-view.jade | 2 +- app/views/courses/CourseDetailsView.coffee | 2 +- app/views/courses/TeacherClassView.coffee | 7 ++++--- app/views/play/CampaignView.coffee | 3 ++- app/views/play/level/PlayLevelView.coffee | 3 +++ app/views/play/level/modal/HeroVictoryModal.coffee | 2 +- app/views/play/level/modal/ProgressView.coffee | 2 +- 13 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/models/Classroom.coffee b/app/models/Classroom.coffee index d855f7bfc..eef817bfb 100644 --- a/app/models/Classroom.coffee +++ b/app/models/Classroom.coffee @@ -87,7 +87,7 @@ module.exports = class Classroom extends CocoModel if options.withoutLadderLevels levels.remove(levels.filter((level) -> level.isLadder())) if options.projectLevels - levels.remove(levels.filter((level) -> not level.isType('game-dev', 'web-dev'))) + levels.remove(levels.filter((level) -> level.get('shareable') isnt 'project')) return levels getLadderLevel: (courseID) -> diff --git a/app/schemas/models/campaign.schema.coffee b/app/schemas/models/campaign.schema.coffee index ff78c8263..82b0eb763 100644 --- a/app/schemas/models/campaign.schema.coffee +++ b/app/schemas/models/campaign.schema.coffee @@ -67,6 +67,7 @@ _.extend CampaignSchema.properties, { adventurer: { type: 'boolean' } practice: { type: 'boolean' } practiceThresholdMinutes: {type: 'number'} + shareable: { title: 'Shareable', type: ['string', 'boolean'], enum: [false, true, 'project'], description: 'Whether the level is not shareable, shareable, or a sharing-encouraged project level.' } adminOnly: { type: 'boolean' } disableSpaces: { type: ['boolean','number'] } hidesSubmitUntilRun: { type: 'boolean' } diff --git a/app/schemas/models/classroom.schema.coffee b/app/schemas/models/classroom.schema.coffee index 9f3e63ca7..e33563b40 100644 --- a/app/schemas/models/classroom.schema.coffee +++ b/app/schemas/models/classroom.schema.coffee @@ -25,7 +25,7 @@ _.extend ClassroomSchema.properties, levels: c.array { title: 'Levels' }, c.object { title: 'Level' }, { practice: {type: 'boolean'} practiceThresholdMinutes: {type: 'number'} - shareable: {type: 'boolean'} + shareable: { title: 'Shareable', type: ['string', 'boolean'], enum: [false, true, 'project'], description: 'Whether the level is not shareable, shareable, or a sharing-encouraged project level.' } type: c.shortString() original: c.objectId() name: {type: 'string'} diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee index f3b311245..75c31b35f 100644 --- a/app/schemas/models/level.coffee +++ b/app/schemas/models/level.coffee @@ -328,8 +328,8 @@ _.extend LevelSchema.properties, replayable: {type: 'boolean', title: 'Replayable', description: 'Whether this (hero) level infinitely scales up its difficulty and can be beaten over and over for greater rewards.'} buildTime: {type: 'number', description: 'How long it has taken to build this level.'} practice: { type: 'boolean' } - shareable: { type: 'boolean', title: 'Shareable' } practiceThresholdMinutes: {type: 'number', description: 'Players with larger playtimes may be directed to a practice level.'} + shareable: { title: 'Shareable', type: ['string', 'boolean'], enum: [false, true, 'project'], description: 'Whether the level is not shareable, shareable, or a sharing-encouraged project level.' } # Admin flags adventurer: { type: 'boolean' } diff --git a/app/styles/courses/teacher-class-view.sass b/app/styles/courses/teacher-class-view.sass index 0a5ab9c0b..66f880ce5 100644 --- a/app/styles/courses/teacher-class-view.sass +++ b/app/styles/courses/teacher-class-view.sass @@ -223,6 +223,9 @@ margin-bottom: 6.5px #student-projects-tab + .student-levels-table + margin-top: 0px + .student-info margin-top: 5px diff --git a/app/templates/courses/course-details.jade b/app/templates/courses/course-details.jade index 6a0c57530..78953cc33 100644 --- a/app/templates/courses/course-details.jade +++ b/app/templates/courses/course-details.jade @@ -106,7 +106,7 @@ block content if previousLevelCompleted || view.teacherMode || !passedLastCompletedLevel || levelStatus - var i18n = level.isType('course-ladder') ? 'play.compete' : 'home.play'; button.btn.btn-success.btn-play-level(data-level-slug=level.get('slug'), data-i18n=i18n, data-level-id=level.get('original')) - if level.isType('game-dev', 'web-dev') + if level.get('shareable') - var levelOriginal = level.get('original'); - var session = view.levelSessions.find(function(session) { return session.get('level').original === levelOriginal }); if session diff --git a/app/templates/play/level/tome/spell-top-bar-view.jade b/app/templates/play/level/tome/spell-top-bar-view.jade index cdacc2c9c..30f0bf1de 100644 --- a/app/templates/play/level/tome/spell-top-bar-view.jade +++ b/app/templates/play/level/tome/spell-top-bar-view.jade @@ -21,7 +21,7 @@ .btn.btn-small.btn-illustrated.hints-button span(data-i18n="play_level.hints") - if view.options.level.isType('game-dev', 'web-dev') + if view.options.level.get('shareable') - var url = '/play/' + view.options.level.get('type') + '-level/' + view.options.level.get('slug') + '/' + view.options.session.id; - if (view.options.courseID) url += '?course=' + view.options.courseID; a.btn.btn-small.btn-illustrated(href=url) diff --git a/app/views/courses/CourseDetailsView.coffee b/app/views/courses/CourseDetailsView.coffee index 8fb01e791..91d10c1f6 100644 --- a/app/views/courses/CourseDetailsView.coffee +++ b/app/views/courses/CourseDetailsView.coffee @@ -52,7 +52,7 @@ module.exports = class CourseDetailsView extends RootView @supermodel.trackRequest(@classroom.fetch()) levelsLoaded = @supermodel.trackRequest(@levels.fetchForClassroomAndCourse(classroomID, @courseID, { - data: { project: 'concepts,practice,type,slug,name,original,description' } + data: { project: 'concepts,practice,type,slug,name,original,description,shareable' } })) @supermodel.trackRequest($.when(levelsLoaded, sessionsLoaded).then(=> diff --git a/app/views/courses/TeacherClassView.coffee b/app/views/courses/TeacherClassView.coffee index 29ec223e1..4aefcc800 100644 --- a/app/views/courses/TeacherClassView.coffee +++ b/app/views/courses/TeacherClassView.coffee @@ -114,13 +114,13 @@ module.exports = class TeacherClassView extends RootView @courses = new Courses() @supermodel.trackRequest @courses.fetch() - + @courseInstances = new CourseInstances() @supermodel.trackRequest @courseInstances.fetchForClassroom(classroomID) @levels = new Levels() - @supermodel.trackRequest @levels.fetchForClassroom(classroomID, {data: {project: 'original,concepts,practice'}}) - + @supermodel.trackRequest @levels.fetchForClassroom(classroomID, {data: {project: 'original,concepts,practice,shareable'}}) + @attachMediatorEvents() window.tracker?.trackEvent 'Teachers Class Loaded', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel'] @@ -389,6 +389,7 @@ module.exports = class TeacherClassView extends RootView not @students.get(userID).isEnrolled() assigningToNobody = selectedIDs.length is 0 @state.set errors: { assigningToNobody, assigningToUnenrolled } + return if assigningToNobody @assignCourse courseID, members window.tracker?.trackEvent 'Teachers Class Students Assign Selected', category: 'Teachers', classroomID: @classroom.id, courseID: courseID, ['Mixpanel'] diff --git a/app/views/play/CampaignView.coffee b/app/views/play/CampaignView.coffee index 641f19e1e..20062873a 100644 --- a/app/views/play/CampaignView.coffee +++ b/app/views/play/CampaignView.coffee @@ -397,7 +397,8 @@ module.exports = class CampaignView extends RootView @particleMan.removeEmitters() @particleMan.attach @$el.find('.map') for level in @campaign.renderedLevels ? {} - particleKey = ['level', @terrain.replace('-branching-test', '')] + terrain = @terrain.replace('-branching-test', '').replace(/(game|web)-dev-\d/, 'forest') + particleKey = ['level', terrain] particleKey.push level.type if level.type and not (level.type in ['hero', 'course']) # Would use isType, but it's not a Level model particleKey.push 'replayable' if level.replayable particleKey.push 'premium' if level.requiresSubscription diff --git a/app/views/play/level/PlayLevelView.coffee b/app/views/play/level/PlayLevelView.coffee index 7ba724ff9..a775a2d53 100644 --- a/app/views/play/level/PlayLevelView.coffee +++ b/app/views/play/level/PlayLevelView.coffee @@ -143,6 +143,7 @@ module.exports = class PlayLevelView extends RootView onLevelLoaded: (e) -> @god = new God({@gameUIState}) unless e.level.isType('web-dev') + @setUpGod() if @waitingToSetUpGod trackLevelLoadEnd: -> return if @isEditorPreview @@ -242,6 +243,8 @@ module.exports = class PlayLevelView extends RootView setupGod: -> return if @level.isType('web-dev') + return @waitingToSetUpGod = true unless @god + @waitingToSetUpGod = undefined @god.setLevel @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false} @god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id] @god.setWorldClassMap @world.classMap diff --git a/app/views/play/level/modal/HeroVictoryModal.coffee b/app/views/play/level/modal/HeroVictoryModal.coffee index 2f55d546b..2b30a5660 100644 --- a/app/views/play/level/modal/HeroVictoryModal.coffee +++ b/app/views/play/level/modal/HeroVictoryModal.coffee @@ -75,7 +75,7 @@ module.exports = class HeroVictoryModal extends ModalView @saveReviewEventually = _.debounce(@saveReviewEventually, 2000) @loadExistingFeedback() - if @level.isType('game-dev', 'web-dev') + if @level.get('shareable') is 'project' @shareURL = "#{window.location.origin}/play/#{@level.get('type')}-level/#{@level.get('slug')}/#{@session.id}" destroy: -> diff --git a/app/views/play/level/modal/ProgressView.coffee b/app/views/play/level/modal/ProgressView.coffee index 23d5879ef..0c35c61da 100644 --- a/app/views/play/level/modal/ProgressView.coffee +++ b/app/views/play/level/modal/ProgressView.coffee @@ -24,7 +24,7 @@ module.exports = class ProgressView extends CocoView # Images in Markdown are like ![description](url) @nextLevel.get('description', true) # Make sure the defaults are available @nextLevelDescription = marked(utils.i18n(@nextLevel.attributesWithDefaults, 'description').replace(/!\[.*?\]\(.*?\)\n*/g, '')) - if @level.isType('game-dev', 'web-dev') + if @level.get('shareable') is 'project' @shareURL = "#{window.location.origin}/play/#{@level.get('type')}-level/#{@level.get('slug')}/#{@session.id}" @shareURL += "?course=#{@course.id}" if @course