diff --git a/app/schemas/models/classroom.schema.coffee b/app/schemas/models/classroom.schema.coffee index 49d655076..4b12a57fb 100644 --- a/app/schemas/models/classroom.schema.coffee +++ b/app/schemas/models/classroom.schema.coffee @@ -8,6 +8,8 @@ _.extend ClassroomSchema.properties, ownerID: c.objectId() description: {type: 'string'} code: c.shortString(title: "Unique code to redeem") + aceConfig: + language: {type: 'string', 'enum': ['python', 'javascript']} c.extendBasicProperties ClassroomSchema, 'Classroom' diff --git a/app/styles/courses/teacher-courses-view.sass b/app/styles/courses/teacher-courses-view.sass index f0bcbabf9..c1ce34b6f 100644 --- a/app/styles/courses/teacher-courses-view.sass +++ b/app/styles/courses/teacher-courses-view.sass @@ -3,6 +3,11 @@ img.media-object width: 300px + + .edit-classroom-small + cursor: pointer + &:hover + color: grey #fixed-area position: fixed diff --git a/app/templates/courses/classroom-settings-modal.jade b/app/templates/courses/classroom-settings-modal.jade new file mode 100644 index 000000000..88064bcd1 --- /dev/null +++ b/app/templates/courses/classroom-settings-modal.jade @@ -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") \ No newline at end of file diff --git a/app/templates/courses/course-details.jade b/app/templates/courses/course-details.jade index dcd5ea98d..5038ada6f 100644 --- a/app/templates/courses/course-details.jade +++ b/app/templates/courses/course-details.jade @@ -53,12 +53,7 @@ block content if courseInstance.get('description') each line in courseInstance.get('description').split('\n') 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') ul.nav.nav-pills(role='tablist') if adminMode @@ -292,27 +287,3 @@ mixin levels-tab if levelConceptMap[levelID][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") diff --git a/app/templates/courses/teacher-courses-view.jade b/app/templates/courses/teacher-courses-view.jade index 4724fb692..196515000 100644 --- a/app/templates/courses/teacher-courses-view.jade +++ b/app/templates/courses/teacher-courses-view.jade @@ -102,7 +102,15 @@ block content a.btn.btn-default.btn-xs(href="/courses/purchase") Add 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}) @@ -111,6 +119,9 @@ block content .progress-bar(style="width: 100%") else + - var description = classroom.get('description'); + if description + p= description table.table tr th Student diff --git a/app/views/courses/ClassroomSettingsModal.coffee b/app/views/courses/ClassroomSettingsModal.coffee new file mode 100644 index 000000000..bd4a5eb1b --- /dev/null +++ b/app/views/courses/ClassroomSettingsModal.coffee @@ -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() + + \ No newline at end of file diff --git a/app/views/courses/CourseDetailsView.coffee b/app/views/courses/CourseDetailsView.coffee index 2c66af160..aa6a0bd2a 100644 --- a/app/views/courses/CourseDetailsView.coffee +++ b/app/views/courses/CourseDetailsView.coffee @@ -19,7 +19,6 @@ module.exports = class CourseDetailsView extends RootView events: 'change .progress-expand-checkbox': 'onCheckExpandedProgress' 'click .btn-play-level': 'onClickPlayLevel' - 'click .btn-save-settings': 'onClickSaveSettings' 'click .btn-select-instance': 'onClickSelectInstance' 'click .progress-member-header': 'onClickMemberHeader' 'click .progress-header': 'onClickProgressHeader' @@ -228,19 +227,6 @@ module.exports = class CourseDetailsView extends RootView getLevelURL: (levelSlug) -> "/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) -> courseInstanceID = $('.select-instance').val() @noCourseInstanceSelected = false diff --git a/app/views/courses/TeacherCoursesView.coffee b/app/views/courses/TeacherCoursesView.coffee index 26cf74ad4..8f6184efa 100644 --- a/app/views/courses/TeacherCoursesView.coffee +++ b/app/views/courses/TeacherCoursesView.coffee @@ -11,6 +11,7 @@ RootView = require 'views/core/RootView' template = require 'templates/courses/teacher-courses-view' utils = require 'core/utils' InviteToClassroomModal = require 'views/courses/InviteToClassroomModal' +ClassroomSettingsModal = require 'views/courses/ClassroomSettingsModal' module.exports = class TeacherCoursesView extends RootView id: 'teacher-courses-view' @@ -22,6 +23,7 @@ module.exports = class TeacherCoursesView extends RootView 'click .course-instance-membership-checkbox': 'onClickCourseInstanceMembershipCheckbox' 'click #save-changes-btn': 'onClickSaveChangesButton' 'click #manage-tab-link': 'onClickManageTabLink' + 'click .edit-classroom-small': 'onClickEditClassroomSmall' constructor: (options) -> super(options) @@ -71,6 +73,13 @@ module.exports = class TeacherCoursesView extends RootView @renderSelectors('#manage-tab-pane') @$('#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) -> classroomID = $(e.target).data('classroom-id') classroom = @classrooms.get(classroomID) diff --git a/server/classrooms/Classroom.coffee b/server/classrooms/Classroom.coffee index 38a2e3018..477d72a50 100644 --- a/server/classrooms/Classroom.coffee +++ b/server/classrooms/Classroom.coffee @@ -11,6 +11,7 @@ ClassroomSchema.statics.privateProperties = [] ClassroomSchema.statics.editableProperties = [ 'description' 'name' + 'aceConfig' ] ClassroomSchema.statics.generateNewCode = (done) -> diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 5ff8732df..049c575e8 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -11,6 +11,7 @@ log = require 'winston' Campaign = require '../campaigns/Campaign' Course = require '../courses/Course' CourseInstance = require '../courses/CourseInstance' +Classroom = require '../classrooms/Classroom' LevelHandler = class LevelHandler extends Handler modelClass: Level @@ -129,10 +130,16 @@ LevelHandler = class LevelHandler extends Handler courses = _.filter(courses, (course) -> course.get('campaignID').toString() in campaignStrings) courseStrings = (course.id.toString() for course in courses) courseInstances = _.filter(courseInstances, (courseInstance) -> courseInstance.get('courseID').toString() in courseStrings) - aceConfigs = (ci.get('aceConfig') for ci in courseInstances) - aceConfig = _.filter(aceConfigs)[0] or {} - req.codeLanguage = aceConfig.language - @createAndSaveNewSession(sessionQuery, req, res) + classroomIDs = (courseInstance.get('classroomID') for courseInstance in courseInstances) + classroomIDs = _.filter _.uniq classroomIDs, false, (objectID='') -> objectID.toString() + if classroomIDs.length + 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 return @sendPaymentRequiredError(res, 'You must be in a course which includes this level to play it') diff --git a/test/server/functional/level.spec.coffee b/test/server/functional/level.spec.coffee index 15e87913f..acb8f000e 100644 --- a/test/server/functional/level.spec.coffee +++ b/test/server/functional/level.spec.coffee @@ -68,29 +68,41 @@ describe 'GET /db/level//session', -> course.save (err) -> expect(err).toBeNull() - + loginJoe (joe) -> - courseInstance = new CourseInstance({ - name: 'Course Instance' - members: [ - joe.get('_id') - ] - courseID: ObjectId(course.id) + classroom = new Classroom({ + name: 'Test Classroom' + members: [ joe.get('_id') ] + aceConfig: { language: 'javascript' } }) - courseInstance.save (err) -> - + classroom.save (err, classroom) -> + 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) -> loginJoe (joe) -> 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(body.codeLanguage).toBe('javascript') done() it 'does not create a new session if the user is not in a course with that level', (done) ->