mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-24 21:44:08 -05:00
Add classroom name, description, and language editing, and classroom language infrastructure
This commit is contained in:
parent
08c7ad71a5
commit
6a54c7cf54
11 changed files with 114 additions and 60 deletions
|
@ -8,6 +8,8 @@ _.extend ClassroomSchema.properties,
|
||||||
ownerID: c.objectId()
|
ownerID: c.objectId()
|
||||||
description: {type: 'string'}
|
description: {type: 'string'}
|
||||||
code: c.shortString(title: "Unique code to redeem")
|
code: c.shortString(title: "Unique code to redeem")
|
||||||
|
aceConfig:
|
||||||
|
language: {type: 'string', 'enum': ['python', 'javascript']}
|
||||||
|
|
||||||
c.extendBasicProperties ClassroomSchema, 'Classroom'
|
c.extendBasicProperties ClassroomSchema, 'Classroom'
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
|
|
||||||
img.media-object
|
img.media-object
|
||||||
width: 300px
|
width: 300px
|
||||||
|
|
||||||
|
.edit-classroom-small
|
||||||
|
cursor: pointer
|
||||||
|
&:hover
|
||||||
|
color: grey
|
||||||
|
|
||||||
#fixed-area
|
#fixed-area
|
||||||
position: fixed
|
position: fixed
|
||||||
|
|
24
app/templates/courses/classroom-settings-modal.jade
Normal file
24
app/templates/courses/classroom-settings-modal.jade
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
extends /templates/core/modal-base
|
||||||
|
|
||||||
|
block modal-header-content
|
||||||
|
button.close(data-dismiss='modal')
|
||||||
|
span ×
|
||||||
|
h3.modal-title(data-i18n="courses.edit_settings1")
|
||||||
|
|
||||||
|
block modal-body-content
|
||||||
|
.form
|
||||||
|
.form-group
|
||||||
|
label(data-i18n="courses.title")
|
||||||
|
input.form-control.settings-name-input(type='text', value="#{view.classroom.get('name') || ''}")
|
||||||
|
.form-group
|
||||||
|
label(data-i18n="courses.description")
|
||||||
|
textarea.form-control.settings-description-input(rows=2)= view.classroom.get('description')
|
||||||
|
.form-group
|
||||||
|
label(data-i18n="choose_hero.programming_language")
|
||||||
|
select.form-control#programming-language-select
|
||||||
|
- var aceConfig = view.classroom.get('aceConfig') || {};
|
||||||
|
option(value="python", selected=aceConfig.language==='python') Python
|
||||||
|
option(value="javascript", selected=aceConfig.language==='javascript') JavaScript
|
||||||
|
|
||||||
|
block modal-footer-content
|
||||||
|
button#save-settings-btn.btn(data-i18n="common.save_changes")
|
|
@ -53,12 +53,7 @@ block content
|
||||||
if courseInstance.get('description')
|
if courseInstance.get('description')
|
||||||
each line in courseInstance.get('description').split('\n')
|
each line in courseInstance.get('description').split('\n')
|
||||||
div= line
|
div= line
|
||||||
// TODO: migrate these settings to classrooms
|
|
||||||
//if adminMode && courseInstance
|
|
||||||
// +settings-dialog
|
|
||||||
// p
|
|
||||||
// button.btn.btn-xs(data-toggle='modal', data-target='#settingsModal', data-i18n="courses.edit_settings")
|
|
||||||
|
|
||||||
div.well.well-sm(role='tabpanel')
|
div.well.well-sm(role='tabpanel')
|
||||||
ul.nav.nav-pills(role='tablist')
|
ul.nav.nav-pills(role='tablist')
|
||||||
if adminMode
|
if adminMode
|
||||||
|
@ -292,27 +287,3 @@ mixin levels-tab
|
||||||
if levelConceptMap[levelID][concept]
|
if levelConceptMap[levelID][concept]
|
||||||
span.spr.progress-level-cell.progress-level-cell-not-started(data-i18n="concepts." + concept)
|
span.spr.progress-level-cell.progress-level-cell-not-started(data-i18n="concepts." + concept)
|
||||||
|
|
||||||
mixin settings-dialog
|
|
||||||
.modal#settingsModal
|
|
||||||
.modal-dialog
|
|
||||||
.modal-header
|
|
||||||
button.close(data-dismiss='modal')
|
|
||||||
span ×
|
|
||||||
h3.modal-title(data-i18n="courses.edit_settings1")
|
|
||||||
.modal-body
|
|
||||||
.form
|
|
||||||
.form-group
|
|
||||||
label(data-i18n="courses.title")
|
|
||||||
input.form-control.settings-name-input(type='text', value="#{courseInstance.get('name') || ''}")
|
|
||||||
.form-group
|
|
||||||
label(data-i18n="courses.description")
|
|
||||||
textarea.form-control.settings-description-input(rows=2)= courseInstance.get('description')
|
|
||||||
.form-group
|
|
||||||
label(data-i18n="choose_hero.programming_language")
|
|
||||||
select.form-control#programming-language-select
|
|
||||||
- var aceConfig = view.courseInstance.get('aceConfig') || {};
|
|
||||||
option(value="python", selected=aceConfig.language==='python') Python
|
|
||||||
option(value="javascript", selected=aceConfig.language==='javascript') JavaScript
|
|
||||||
|
|
||||||
.modal-footer
|
|
||||||
button.btn.btn-save-settings(data-i18n="common.save_changes")
|
|
||||||
|
|
|
@ -102,7 +102,15 @@ block content
|
||||||
a.btn.btn-default.btn-xs(href="/courses/purchase") Add
|
a.btn.btn-default.btn-xs(href="/courses/purchase") Add
|
||||||
|
|
||||||
for classroom in view.classrooms.models
|
for classroom in view.classrooms.models
|
||||||
h2= classroom.get('name')
|
h2
|
||||||
|
span.spr= classroom.get('name')
|
||||||
|
- var language = (classroom.get('aceConfig') || {}).language || 'python';
|
||||||
|
if language === 'python'
|
||||||
|
img(src="/images/common/code_languages/python_icon.png")
|
||||||
|
if language === 'javascript'
|
||||||
|
img(src="/images/common/code_languages/javascript_icon.png")
|
||||||
|
small.spl.edit-classroom-small(data-classroom-id=classroom.id)
|
||||||
|
span.glyphicon.glyphicon-pencil
|
||||||
|
|
||||||
- var courseInstances = view.courseInstances.where({classroomID: classroom.id})
|
- var courseInstances = view.courseInstances.where({classroomID: classroom.id})
|
||||||
|
|
||||||
|
@ -111,6 +119,9 @@ block content
|
||||||
.progress-bar(style="width: 100%")
|
.progress-bar(style="width: 100%")
|
||||||
|
|
||||||
else
|
else
|
||||||
|
- var description = classroom.get('description');
|
||||||
|
if description
|
||||||
|
p= description
|
||||||
table.table
|
table.table
|
||||||
tr
|
tr
|
||||||
th Student
|
th Student
|
||||||
|
|
26
app/views/courses/ClassroomSettingsModal.coffee
Normal file
26
app/views/courses/ClassroomSettingsModal.coffee
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
ModalView = require 'views/core/ModalView'
|
||||||
|
template = require 'templates/courses/classroom-settings-modal'
|
||||||
|
|
||||||
|
module.exports = class AddLevelSystemModal extends ModalView
|
||||||
|
id: 'classroom-settings-modal'
|
||||||
|
template: template
|
||||||
|
|
||||||
|
events:
|
||||||
|
'click #save-settings-btn': 'onClickSaveSettingsButton'
|
||||||
|
|
||||||
|
initialize: (options) ->
|
||||||
|
@classroom = options.classroom
|
||||||
|
|
||||||
|
onClickSaveSettingsButton: ->
|
||||||
|
return unless @classroom
|
||||||
|
if name = $('.settings-name-input').val()
|
||||||
|
@classroom.set('name', name)
|
||||||
|
description = $('.settings-description-input').val()
|
||||||
|
@classroom.set('description', description)
|
||||||
|
@classroom.set('aceConfig', {
|
||||||
|
language: @$('#programming-language-select').val()
|
||||||
|
})
|
||||||
|
@classroom.patch()
|
||||||
|
@hide()
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ module.exports = class CourseDetailsView extends RootView
|
||||||
events:
|
events:
|
||||||
'change .progress-expand-checkbox': 'onCheckExpandedProgress'
|
'change .progress-expand-checkbox': 'onCheckExpandedProgress'
|
||||||
'click .btn-play-level': 'onClickPlayLevel'
|
'click .btn-play-level': 'onClickPlayLevel'
|
||||||
'click .btn-save-settings': 'onClickSaveSettings'
|
|
||||||
'click .btn-select-instance': 'onClickSelectInstance'
|
'click .btn-select-instance': 'onClickSelectInstance'
|
||||||
'click .progress-member-header': 'onClickMemberHeader'
|
'click .progress-member-header': 'onClickMemberHeader'
|
||||||
'click .progress-header': 'onClickProgressHeader'
|
'click .progress-header': 'onClickProgressHeader'
|
||||||
|
@ -228,19 +227,6 @@ module.exports = class CourseDetailsView extends RootView
|
||||||
getLevelURL: (levelSlug) ->
|
getLevelURL: (levelSlug) ->
|
||||||
"/play/level/#{levelSlug}?course=#{@courseID}&course-instance=#{@courseInstanceID}"
|
"/play/level/#{levelSlug}?course=#{@courseID}&course-instance=#{@courseInstanceID}"
|
||||||
|
|
||||||
onClickSaveSettings: (e) ->
|
|
||||||
return unless @courseInstance
|
|
||||||
if name = $('.settings-name-input').val()
|
|
||||||
@courseInstance.set('name', name)
|
|
||||||
description = $('.settings-description-input').val()
|
|
||||||
console.log 'onClickSaveSettings', description
|
|
||||||
@courseInstance.set('description', description)
|
|
||||||
@courseInstance.set('aceConfig', {
|
|
||||||
language: @$('#programming-language-select').val()
|
|
||||||
})
|
|
||||||
@courseInstance.patch()
|
|
||||||
$('#settingsModal').modal('hide')
|
|
||||||
|
|
||||||
onClickSelectInstance: (e) ->
|
onClickSelectInstance: (e) ->
|
||||||
courseInstanceID = $('.select-instance').val()
|
courseInstanceID = $('.select-instance').val()
|
||||||
@noCourseInstanceSelected = false
|
@noCourseInstanceSelected = false
|
||||||
|
|
|
@ -11,6 +11,7 @@ RootView = require 'views/core/RootView'
|
||||||
template = require 'templates/courses/teacher-courses-view'
|
template = require 'templates/courses/teacher-courses-view'
|
||||||
utils = require 'core/utils'
|
utils = require 'core/utils'
|
||||||
InviteToClassroomModal = require 'views/courses/InviteToClassroomModal'
|
InviteToClassroomModal = require 'views/courses/InviteToClassroomModal'
|
||||||
|
ClassroomSettingsModal = require 'views/courses/ClassroomSettingsModal'
|
||||||
|
|
||||||
module.exports = class TeacherCoursesView extends RootView
|
module.exports = class TeacherCoursesView extends RootView
|
||||||
id: 'teacher-courses-view'
|
id: 'teacher-courses-view'
|
||||||
|
@ -22,6 +23,7 @@ module.exports = class TeacherCoursesView extends RootView
|
||||||
'click .course-instance-membership-checkbox': 'onClickCourseInstanceMembershipCheckbox'
|
'click .course-instance-membership-checkbox': 'onClickCourseInstanceMembershipCheckbox'
|
||||||
'click #save-changes-btn': 'onClickSaveChangesButton'
|
'click #save-changes-btn': 'onClickSaveChangesButton'
|
||||||
'click #manage-tab-link': 'onClickManageTabLink'
|
'click #manage-tab-link': 'onClickManageTabLink'
|
||||||
|
'click .edit-classroom-small': 'onClickEditClassroomSmall'
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super(options)
|
super(options)
|
||||||
|
@ -71,6 +73,13 @@ module.exports = class TeacherCoursesView extends RootView
|
||||||
@renderSelectors('#manage-tab-pane')
|
@renderSelectors('#manage-tab-pane')
|
||||||
@$('#manage-tab-pane').toggleClass('active', isActive)
|
@$('#manage-tab-pane').toggleClass('active', isActive)
|
||||||
|
|
||||||
|
onClickEditClassroomSmall: (e) ->
|
||||||
|
classroomID = $(e.target).closest('small').data('classroom-id')
|
||||||
|
classroom = @classrooms.get(classroomID)
|
||||||
|
modal = new ClassroomSettingsModal({classroom: classroom})
|
||||||
|
@openModalView(modal)
|
||||||
|
@listenToOnce modal, 'hide', @renderManageTab
|
||||||
|
|
||||||
onClickAddStudentsButton: (e) ->
|
onClickAddStudentsButton: (e) ->
|
||||||
classroomID = $(e.target).data('classroom-id')
|
classroomID = $(e.target).data('classroom-id')
|
||||||
classroom = @classrooms.get(classroomID)
|
classroom = @classrooms.get(classroomID)
|
||||||
|
|
|
@ -11,6 +11,7 @@ ClassroomSchema.statics.privateProperties = []
|
||||||
ClassroomSchema.statics.editableProperties = [
|
ClassroomSchema.statics.editableProperties = [
|
||||||
'description'
|
'description'
|
||||||
'name'
|
'name'
|
||||||
|
'aceConfig'
|
||||||
]
|
]
|
||||||
|
|
||||||
ClassroomSchema.statics.generateNewCode = (done) ->
|
ClassroomSchema.statics.generateNewCode = (done) ->
|
||||||
|
|
|
@ -11,6 +11,7 @@ log = require 'winston'
|
||||||
Campaign = require '../campaigns/Campaign'
|
Campaign = require '../campaigns/Campaign'
|
||||||
Course = require '../courses/Course'
|
Course = require '../courses/Course'
|
||||||
CourseInstance = require '../courses/CourseInstance'
|
CourseInstance = require '../courses/CourseInstance'
|
||||||
|
Classroom = require '../classrooms/Classroom'
|
||||||
|
|
||||||
LevelHandler = class LevelHandler extends Handler
|
LevelHandler = class LevelHandler extends Handler
|
||||||
modelClass: Level
|
modelClass: Level
|
||||||
|
@ -129,10 +130,16 @@ LevelHandler = class LevelHandler extends Handler
|
||||||
courses = _.filter(courses, (course) -> course.get('campaignID').toString() in campaignStrings)
|
courses = _.filter(courses, (course) -> course.get('campaignID').toString() in campaignStrings)
|
||||||
courseStrings = (course.id.toString() for course in courses)
|
courseStrings = (course.id.toString() for course in courses)
|
||||||
courseInstances = _.filter(courseInstances, (courseInstance) -> courseInstance.get('courseID').toString() in courseStrings)
|
courseInstances = _.filter(courseInstances, (courseInstance) -> courseInstance.get('courseID').toString() in courseStrings)
|
||||||
aceConfigs = (ci.get('aceConfig') for ci in courseInstances)
|
classroomIDs = (courseInstance.get('classroomID') for courseInstance in courseInstances)
|
||||||
aceConfig = _.filter(aceConfigs)[0] or {}
|
classroomIDs = _.filter _.uniq classroomIDs, false, (objectID='') -> objectID.toString()
|
||||||
req.codeLanguage = aceConfig.language
|
if classroomIDs.length
|
||||||
@createAndSaveNewSession(sessionQuery, req, res)
|
Classroom.find({ _id: { $in: classroomIDs }}).exec (err, classrooms) =>
|
||||||
|
aceConfigs = (c.get('aceConfig') for c in classrooms)
|
||||||
|
aceConfig = _.filter(aceConfigs)[0] or {}
|
||||||
|
req.codeLanguage = aceConfig.language
|
||||||
|
@createAndSaveNewSession(sessionQuery, req, res)
|
||||||
|
else
|
||||||
|
@createAndSaveNewSession(sessionQuery, req, res)
|
||||||
else
|
else
|
||||||
return @sendPaymentRequiredError(res, 'You must be in a course which includes this level to play it')
|
return @sendPaymentRequiredError(res, 'You must be in a course which includes this level to play it')
|
||||||
|
|
||||||
|
|
|
@ -68,29 +68,41 @@ describe 'GET /db/level/<id>/session', ->
|
||||||
course.save (err) ->
|
course.save (err) ->
|
||||||
|
|
||||||
expect(err).toBeNull()
|
expect(err).toBeNull()
|
||||||
|
|
||||||
loginJoe (joe) ->
|
loginJoe (joe) ->
|
||||||
|
|
||||||
courseInstance = new CourseInstance({
|
classroom = new Classroom({
|
||||||
name: 'Course Instance'
|
name: 'Test Classroom'
|
||||||
members: [
|
members: [ joe.get('_id') ]
|
||||||
joe.get('_id')
|
aceConfig: { language: 'javascript' }
|
||||||
]
|
|
||||||
courseID: ObjectId(course.id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
courseInstance.save (err) ->
|
classroom.save (err, classroom) ->
|
||||||
|
|
||||||
expect(err).toBeNull()
|
expect(err).toBeNull()
|
||||||
done()
|
|
||||||
|
courseInstance = new CourseInstance({
|
||||||
|
name: 'Course Instance'
|
||||||
|
members: [
|
||||||
|
joe.get('_id')
|
||||||
|
]
|
||||||
|
courseID: ObjectId(course.id)
|
||||||
|
classroomID: ObjectId(classroom.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
courseInstance.save (err) ->
|
||||||
|
|
||||||
|
expect(err).toBeNull()
|
||||||
|
done()
|
||||||
|
|
||||||
it 'creates a new session if the user is in a course with that level', (done) ->
|
it 'creates a new session if the user is in a course with that level', (done) ->
|
||||||
loginJoe (joe) ->
|
loginJoe (joe) ->
|
||||||
|
|
||||||
url = getURL("/db/level/#{levelID}/session")
|
url = getURL("/db/level/#{levelID}/session")
|
||||||
|
|
||||||
request.get { uri: url }, (err, res, body) ->
|
request.get { uri: url, json: true }, (err, res, body) ->
|
||||||
expect(res.statusCode).toBe(200)
|
expect(res.statusCode).toBe(200)
|
||||||
|
expect(body.codeLanguage).toBe('javascript')
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'does not create a new session if the user is not in a course with that level', (done) ->
|
it 'does not create a new session if the user is not in a course with that level', (done) ->
|
||||||
|
|
Loading…
Reference in a new issue