config = require '../../../server_config' require '../common' clientUtils = require '../../../app/core/utils' # Must come after require /common utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' request = require '../request' requestAsync = Promise.promisify(request, {multiArgs: true}) User = require '../../../server/models/User' Classroom = require '../../../server/models/Classroom' Course = require '../../../server/models/Course' CourseInstance = require '../../../server/models/CourseInstance' Campaign = require '../../../server/models/Campaign' LevelSession = require '../../../server/models/LevelSession' Level = require '../../../server/models/Level' classroomsURL = getURL('/db/classroom') describe 'GET /db/classroom?ownerID=:id', -> beforeEach utils.wrap (done) -> yield utils.clearModels([User, Classroom]) @user1 = yield utils.initUser() yield utils.loginUser(@user1) @classroom1 = yield new Classroom({name: 'Classroom 1', ownerID: @user1.get('_id') }).save() @user2 = yield utils.initUser() yield utils.loginUser(@user2) @classroom2 = yield new Classroom({name: 'Classroom 2', ownerID: @user2.get('_id') }).save() done() it 'returns an array of classrooms with the given owner', utils.wrap (done) -> [res, body] = yield request.getAsync getURL('/db/classroom?ownerID='+@user2.id), { json: true } expect(res.statusCode).toBe(200) expect(body.length).toBe(1) expect(body[0].name).toBe('Classroom 2') done() it 'returns 403 when a non-admin tries to get classrooms for another user', utils.wrap (done) -> [res, body] = yield request.getAsync getURL('/db/classroom?ownerID='+@user1.id), { json: true } expect(res.statusCode).toBe(403) done() describe 'GET /db/classroom/:id', -> it 'clears database users and classrooms', (done) -> clearModels [User, Classroom], (err) -> throw err if err done() it 'returns the classroom for the given id', (done) -> loginNewUser (user1) -> user1.set('role', 'teacher') user1.save (err) -> data = { name: 'Classroom 1' } request.post {uri: classroomsURL, json: data }, (err, res, body) -> expect(res.statusCode).toBe(201) classroomID = body._id request.get {uri: classroomsURL + '/' + body._id }, (err, res, body) -> expect(res.statusCode).toBe(200) expect(body._id).toBe(classroomID = body._id) done() describe 'GET /db/classroom by classCode', -> it 'Returns the class if you include spaces', utils.wrap (done) -> user = yield utils.initUser() yield utils.loginUser(user) teacher = yield utils.initUser() classroom = new Classroom({ name: "some class", ownerID: teacher.id, camelCode: "FooBarBaz", code: "foobarbaz" }) yield classroom.save() [res, body] = yield request.getAsync(getURL('/db/classroom?code=foo bar baz'), { json: true }) expect(res.statusCode).toBe(200) expect(res.body.data?.name).toBe(classroom.get('name')) done() describe 'POST /db/classroom', -> beforeEach utils.wrap (done) -> yield utils.clearModels [User, Classroom, Course, Level, Campaign] admin = yield utils.initAdmin() yield utils.loginUser(admin) levelJSONA = { name: 'Level A', permissions: [{access: 'owner', target: admin.id}], type: 'course' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONA}) expect(res.statusCode).toBe(200) @levelA = yield Level.findById(res.body._id) levelJSONB = { name: 'Level B', permissions: [{access: 'owner', target: admin.id}], type: 'course' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONB}) expect(res.statusCode).toBe(200) @levelB = yield Level.findById(res.body._id) levelJSONC = { name: 'Level C', permissions: [{access: 'owner', target: admin.id}], type: 'hero', practice: true } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONC}) expect(res.statusCode).toBe(200) @levelC = yield Level.findById(res.body._id) levelJSONJSPrimer1 = { name: 'JS Primer 1', permissions: [{access: 'owner', target: admin.id}], type: 'hero', primerLanguage: 'javascript' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONJSPrimer1}) expect(res.statusCode).toBe(200) @levelJSPrimer1 = yield Level.findById(res.body._id) campaignJSON = { name: 'Campaign', levels: {} } paredLevelJSPrimer1 = _.pick(@levelJSPrimer1.toObject(), 'name', 'original', 'type', 'slug', 'primerLanguage') paredLevelJSPrimer1.campaignIndex = 3 campaignJSON.levels[@levelJSPrimer1.get('original').toString()] = paredLevelJSPrimer1 paredLevelC = _.pick(@levelC.toObject(), 'name', 'original', 'type', 'slug', 'practice') paredLevelC.campaignIndex = 2 campaignJSON.levels[@levelC.get('original').toString()] = paredLevelC paredLevelB = _.pick(@levelB.toObject(), 'name', 'original', 'type', 'slug') paredLevelB.campaignIndex = 1 campaignJSON.levels[@levelB.get('original').toString()] = paredLevelB paredLevelA = _.pick(@levelA.toObject(), 'name', 'original', 'type', 'slug') paredLevelA.campaignIndex = 0 campaignJSON.levels[@levelA.get('original').toString()] = paredLevelA [res, body] = yield request.postAsync({uri: getURL('/db/campaign'), json: campaignJSON}) @campaign = yield Campaign.findById(res.body._id) @course = Course({name: 'Course', campaignID: @campaign._id, releasePhase: 'released'}) yield @course.save() done() it 'creates a new classroom for the given user with teacher role', utils.wrap (done) -> teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(teacher) data = { name: 'Classroom 1' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } expect(res.statusCode).toBe(201) expect(res.body.name).toBe('Classroom 1') expect(res.body.members.length).toBe(0) expect(res.body.ownerID).toBe(teacher.id) done() it 'returns 401 for anonymous users', utils.wrap (done) -> yield utils.logout() data = { name: 'Classroom 2' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } expect(res.statusCode).toBe(401) done() it 'does not work for non-teacher users', utils.wrap (done) -> user = yield utils.initUser() yield utils.loginUser(user) data = { name: 'Classroom 1' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } expect(res.statusCode).toBe(403) done() describe 'when javascript classroom', -> beforeEach utils.wrap (done) -> teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(teacher) data = { name: 'Classroom 2', aceConfig: { language: 'javascript' } } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } @classroom = yield Classroom.findById(res.body._id) done() it 'makes a copy of the list of all levels in all courses', utils.wrap (done) -> expect(@classroom.get('courses')[0].levels.length).toEqual(3) expect(@classroom.get('courses')[0].levels[0].original.toString()).toBe(@levelA.get('original').toString()) expect(@classroom.get('courses')[0].levels[0].type).toBe('course') expect(@classroom.get('courses')[0].levels[0].slug).toBe('level-a') expect(@classroom.get('courses')[0].levels[0].name).toBe('Level A') done() describe 'when python classroom', -> beforeEach utils.wrap (done) -> teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(teacher) data = { name: 'Classroom 2', aceConfig: { language: 'python' } } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } @classroom = yield Classroom.findById(res.body._id) done() it 'makes a copy all levels in all courses', utils.wrap (done) -> expect(@classroom.get('courses')[0].levels.length).toEqual(4) expect(@classroom.get('courses')[0].levels[0].original.toString()).toBe(@levelA.get('original').toString()) expect(@classroom.get('courses')[0].levels[0].type).toBe('course') expect(@classroom.get('courses')[0].levels[0].slug).toBe('level-a') expect(@classroom.get('courses')[0].levels[0].name).toBe('Level A') done() describe 'when there are unreleased courses', -> beforeEach utils.wrap (done) -> admin = yield utils.initAdmin() yield utils.loginUser(admin) betaLevelJSON = { name: 'Beta Level', permissions: [{access: 'owner', target: admin.id}], type: 'course' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: betaLevelJSON}) expect(res.statusCode).toBe(200) @betaLevel = yield Level.findById(res.body._id) betaCampaignJSON = { name: 'Beta Campaign', levels: {} } paredBetaLevel = _.pick(@betaLevel.toObject(), 'name', 'original', 'type', 'slug') paredBetaLevel.campaignIndex = 0 betaCampaignJSON.levels[@betaLevel.get('original').toString()] = paredBetaLevel [res, body] = yield request.postAsync({uri: getURL('/db/campaign'), json: betaCampaignJSON}) @betaCampaign = yield Campaign.findById(res.body._id) @betaCourse = Course({name: 'Beta Course', campaignID: @betaCampaign._id, releasePhase: 'beta'}) yield @betaCourse.save() done() it 'includes unreleased courses for admin teachers', utils.wrap (done) -> adminTeacher = yield utils.initUser({ role: 'teacher', permissions: ['admin'] }) yield utils.loginUser(adminTeacher) data = { name: 'Classroom 3' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(2) expect(classroom.get('courses')[0].levels[0].original.toString()).toBe(@levelA.get('original').toString()) expect(classroom.get('courses')[0].levels[0].type).toBe('course') expect(classroom.get('courses')[0].levels[0].slug).toBe('level-a') expect(classroom.get('courses')[0].levels[0].name).toBe('Level A') expect(classroom.get('courses')[1].levels[0].original.toString()).toBe(@betaLevel.get('original').toString()) expect(classroom.get('courses')[1].levels[0].type).toBe('course') expect(classroom.get('courses')[1].levels[0].slug).toBe('beta-level') expect(classroom.get('courses')[1].levels[0].name).toBe('Beta Level') done() it 'does not include unreleased courses for non-admin teachers', utils.wrap (done) -> teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(teacher) data = { name: 'Classroom 4' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(1) expect(classroom.get('courses')[0].levels[0].original.toString()).toBe(@levelA.get('original').toString()) expect(classroom.get('courses')[0].levels[0].type).toBe('course') expect(classroom.get('courses')[0].levels[0].slug).toBe('level-a') expect(classroom.get('courses')[0].levels[0].name).toBe('Level A') done() describe 'GET /db/classroom/:handle/levels', -> beforeEach utils.wrap (done) -> yield utils.clearModels [User, Classroom, Course, Level, Campaign] admin = yield utils.initAdmin() yield utils.loginUser(admin) levelJSON = { name: 'A', permissions: [{access: 'owner', target: admin.id}], type: 'course' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSON}) expect(res.statusCode).toBe(200) @levelA = yield Level.findById(res.body._id) paredLevelA = _.pick(res.body, 'name', 'original', 'type') levelJSON = { name: 'B', permissions: [{access: 'owner', target: admin.id}], type: 'course' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSON}) expect(res.statusCode).toBe(200) @levelB = yield Level.findById(res.body._id) paredLevelB = _.pick(res.body, 'name', 'original', 'type') levelJSON = { name: 'JS Primer 1', permissions: [{access: 'owner', target: admin.id}], type: 'course', primerLanguage: 'javascript' } [res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSON}) expect(res.statusCode).toBe(200) @levelJSPrimer1 = yield Level.findById(res.body._id) paredLevelJSPrimer1 = _.pick(res.body, 'name', 'original', 'type') campaignJSONA = { name: 'Campaign A', levels: {} } campaignJSONA.levels[paredLevelA.original] = paredLevelA [res, body] = yield request.postAsync({uri: getURL('/db/campaign'), json: campaignJSONA}) @campaignA = yield Campaign.findById(res.body._id) campaignJSONB = { name: 'Campaign B', levels: {} } campaignJSONB.levels[paredLevelB.original] = paredLevelB campaignJSONB.levels[paredLevelJSPrimer1.original] = paredLevelJSPrimer1 [res, body] = yield request.postAsync({uri: getURL('/db/campaign'), json: campaignJSONB}) @campaignB = yield Campaign.findById(res.body._id) @courseA = Course({name: 'Course A', campaignID: @campaignA._id, releasePhase: 'released'}) yield @courseA.save() @courseB = Course({name: 'Course B', campaignID: @campaignB._id, releasePhase: 'released'}) yield @courseB.save() done() describe 'when javascript classroom', -> beforeEach utils.wrap (done) -> teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(teacher) data = { name: 'Classroom 1', aceConfig: { language: 'javascript' } } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } expect(res.statusCode).toBe(201) @classroom = yield Classroom.findById(res.body._id) done() it 'returns all levels referenced in in the classroom\'s copy of course levels', utils.wrap (done) -> [res, body] = yield request.getAsync { uri: getURL("/db/classroom/#{@classroom.id}/levels"), json: true } expect(res.statusCode).toBe(200) levels = res.body expect(levels.length).toBe(2) [res, body] = yield request.getAsync { uri: getURL("/db/classroom/#{@classroom.id}/courses/#{@courseA.id}/levels"), json: true } expect(res.statusCode).toBe(200) levels = res.body expect(levels.length).toBe(1) expect(levels[0].original).toBe(@levelA.get('original').toString()) [res, body] = yield request.getAsync { uri: getURL("/db/classroom/#{@classroom.id}/courses/#{@courseB.id}/levels"), json: true } expect(res.statusCode).toBe(200) levels = res.body expect(levels.length).toBe(1) expect(levels[0].original).toBe(@levelB.get('original').toString()) done() describe 'when python classroom', -> beforeEach utils.wrap (done) -> teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(teacher) data = { name: 'Classroom 1', aceConfig: { language: 'python' } } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } expect(res.statusCode).toBe(201) @classroom = yield Classroom.findById(res.body._id) done() it 'returns all levels referenced in in the classroom\'s copy of course levels', utils.wrap (done) -> [res, body] = yield request.getAsync { uri: getURL("/db/classroom/#{@classroom.id}/levels"), json: true } expect(res.statusCode).toBe(200) levels = res.body expect(levels.length).toBe(3) [res, body] = yield request.getAsync { uri: getURL("/db/classroom/#{@classroom.id}/courses/#{@courseA.id}/levels"), json: true } expect(res.statusCode).toBe(200) levels = res.body expect(levels.length).toBe(1) expect(levels[0].original).toBe(@levelA.get('original').toString()) [res, body] = yield request.getAsync { uri: getURL("/db/classroom/#{@classroom.id}/courses/#{@courseB.id}/levels"), json: true } expect(res.statusCode).toBe(200) levels = res.body expect(levels.length).toBe(2) expect(levels[0].original).toBe(@levelB.get('original').toString()) expect(levels[1].original).toBe(@levelJSPrimer1.get('original').toString()) done() describe 'PUT /db/classroom', -> it 'clears database users and classrooms', (done) -> clearModels [User, Classroom], (err) -> throw err if err done() it 'edits name and description', (done) -> loginNewUser (user1) -> user1.set('role', 'teacher') user1.save (err) -> data = { name: 'Classroom 2' } request.post {uri: classroomsURL, json: data }, (err, res, body) -> expect(res.statusCode).toBe(201) data = { name: 'Classroom 3', description: 'New Description' } url = classroomsURL + '/' + body._id request.put { uri: url, json: data }, (err, res, body) -> expect(body.name).toBe('Classroom 3') expect(body.description).toBe('New Description') done() it 'is not allowed if you are just a member', (done) -> loginNewUser (user1) -> user1.set('role', 'teacher') user1.save (err) -> data = { name: 'Classroom 4' } request.post {uri: classroomsURL, json: data }, (err, res, body) -> expect(res.statusCode).toBe(201) classroomCode = body.code loginNewUser (user2) -> url = getURL("/db/classroom/~/members") data = { code: classroomCode } request.post { uri: url, json: data }, (err, res, body) -> expect(res.statusCode).toBe(200) url = classroomsURL + '/' + body._id request.put { uri: url, json: data }, (err, res, body) -> expect(res.statusCode).toBe(403) done() describe 'POST /db/classroom/-/members', -> beforeEach utils.wrap (done) -> yield utils.clearModels([User, Classroom, Course, Campaign]) @campaign = new Campaign({levels: {}}) yield @campaign.save() @course = new Course({free: true, campaignID: @campaign._id, releasePhase: 'released'}) yield @course.save() @teacher = yield utils.initUser({role: 'teacher'}) yield utils.loginUser(@teacher) [res, body] = yield request.postAsync({uri: classroomsURL, json: { name: 'Classroom 5' } }) expect(res.statusCode).toBe(201) @classroom = yield Classroom.findById(body._id) [res, body] = yield request.postAsync({uri: getURL('/db/course_instance'), json: { courseID: @course.id, classroomID: @classroom.id }}) expect(res.statusCode).toBe(200) @courseInstance = yield CourseInstance.findById(res.body._id) @student = yield utils.initUser() done() it 'adds the signed in user to the classroom and any free courses and sets role to student', utils.wrap (done) -> yield utils.loginUser(@student) url = getURL("/db/classroom/anything-here/members") [res, body] = yield request.postAsync { uri: url, json: { code: @classroom.get('code') } } expect(res.statusCode).toBe(200) classroom = yield Classroom.findById(@classroom.id) expect(classroom.get('members').length).toBe(1) expect(classroom.get('members')?[0]?.equals(@student._id)).toBe(true) student = yield User.findById(@student.id) if student.get('role') isnt 'student' fail('student role should be "student"') unless student.get('courseInstances')?[0].equals(@courseInstance._id) fail('student should be added to the free course instance.') done() it 'joins the class even with spaces in the classcode', utils.wrap (done) -> yield utils.loginUser(@student) url = getURL("/db/classroom/anything-here/members") code = @classroom.get('code') codeWithSpaces = code.split("").join(" ") [res, body] = yield request.postAsync { uri: url, json: { code: codeWithSpaces } } expect(res.statusCode).toBe(200) classroom = yield Classroom.findById(@classroom.id) if classroom.get('members').length isnt 1 fail 'expected classCode with spaces to work too' done() it 'returns 403 if the user is a teacher', utils.wrap (done) -> yield utils.loginUser(@teacher) url = getURL("/db/classroom/~/members") [res, body] = yield request.postAsync { uri: url, json: { code: @classroom.get('code') } } expect(res.statusCode).toBe(403) done() it 'returns 401 if the user is anonymous', utils.wrap (done) -> yield utils.becomeAnonymous() [res, body] = yield request.postAsync { uri: getURL("/db/classroom/-/members"), json: { code: @classroom.get('code') } } expect(res.statusCode).toBe(401) done() describe 'DELETE /db/classroom/:id/members', -> it 'clears database users and classrooms', (done) -> clearModels [User, Classroom], (err) -> throw err if err done() it 'removes the given user from the list of members in the classroom', (done) -> loginNewUser (user1) -> user1.set('role', 'teacher') user1.save (err) -> data = { name: 'Classroom 6' } request.post {uri: classroomsURL, json: data }, (err, res, body) -> classroomCode = body.code classroomID = body._id expect(res.statusCode).toBe(201) loginNewUser (user2) -> url = getURL("/db/classroom/~/members") data = { code: classroomCode } request.post { uri: url, json: data }, (err, res, body) -> expect(res.statusCode).toBe(200) Classroom.findById classroomID, (err, classroom) -> expect(classroom.get('members').length).toBe(1) url = getURL("/db/classroom/#{classroom.id}/members") data = { userID: user2.id } request.del { uri: url, json: data }, (err, res, body) -> expect(res.statusCode).toBe(200) Classroom.findById classroomID, (err, classroom) -> expect(classroom.get('members').length).toBe(0) done() describe 'POST /db/classroom/:id/invite-members', -> it 'takes a list of emails and sends invites', utils.wrap (done) -> user = yield utils.initUser({role: 'teacher', name: 'Mr Professerson'}) yield utils.loginUser(user) classroom = yield utils.makeClassroom() url = classroomsURL + "/#{classroom.id}/invite-members" data = { emails: ['test@test.com'] } sendwithus = require '../../../server/sendwithus' spyOn(sendwithus.api, 'send').and.callFake (context, cb) -> expect(context.email_id).toBe(sendwithus.templates.course_invite_email) expect(context.recipient.address).toBe('test@test.com') expect(context.email_data.teacher_name).toBe('Mr Professerson') done() [res, body] = yield request.postAsync { uri: url, json: data } expect(res.statusCode).toBe(200) describe 'GET /db/classroom/:handle/member-sessions', -> beforeEach utils.wrap (done) -> yield utils.clearModels([CourseInstance, Course, User, Classroom, Campaign, Level, LevelSession]) @teacher = yield utils.initUser({role: 'teacher'}) admin = yield utils.initAdmin() yield utils.loginUser(admin) @levelA = yield utils.makeLevel({type: 'course'}) @levelB = yield utils.makeLevel({type: 'course'}) @campaignA = yield utils.makeCampaign({}, {levels: [@levelA]}) @campaignB = yield utils.makeCampaign({}, {levels: [@levelB]}) @courseA = yield utils.makeCourse({free: true, releasePhase: 'released'}, {campaign: @campaignA}) @courseB = yield utils.makeCourse({free: true, releasePhase: 'released'}, {campaign: @campaignB}) @student1 = yield utils.initUser({role: 'student'}) @student2 = yield utils.initUser({role: 'student'}) @session1A = yield utils.makeLevelSession({state: { complete: true }}, {creator: @student1, level: @levelA}) @session1B = yield utils.makeLevelSession({state: { complete: false }}, {creator: @student1, level: @levelB}) @session2A = yield utils.makeLevelSession({state: { complete: true }}, {creator: @student2, level: @levelA}) @session2B = yield utils.makeLevelSession({state: { complete: false }}, {creator: @student2, level: @levelB}) yield utils.loginUser(@teacher) @classroom = yield utils.makeClassroom({}, { members: [@student1, @student2] }) @courseInstanceA = yield utils.makeCourseInstance({courseID: @courseA.id, classroomID: @classroom.id}, { members: [@student1, @student2] }) @courseInstanceB = yield utils.makeCourseInstance({courseID: @courseB.id, classroomID: @classroom.id}, { members: [@student1] }) yield utils.logout() done() it 'returns all sessions for all members in the classroom with assigned courses', utils.wrap (done) -> yield utils.loginUser(@teacher) [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions"), { json: true } expect(res.statusCode).toBe(200) expect(body.length).toBe(3) done() it 'does not work if you are not the owner of the classroom', utils.wrap (done) -> yield utils.loginUser(@student1) [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions"), { json: true } expect(res.statusCode).toBe(403) done() it 'does not work if you are not logged in', utils.wrap (done) -> [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions"), { json: true } expect(res.statusCode).toBe(401) done() it 'accepts memberSkip and memberLimit GET parameters', utils.wrap (done) -> yield utils.loginUser(@teacher) [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions?memberLimit=1"), { json: true } expect(res.statusCode).toBe(200) expect(body.length).toBe(2) expect(session.creator).toBe(@student1.id) for session in body [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions?memberSkip=1"), { json: true } expect(res.statusCode).toBe(200) expect(body.length).toBe(1) expect(session.creator).toBe(@student2.id) for session in body done() describe 'GET /db/classroom/:handle/members', -> beforeEach utils.wrap (done) -> yield utils.clearModels([User, Classroom]) @teacher = yield utils.initUser() @student1 = yield utils.initUser({ name: "Firstname Lastname" }) @student2 = yield utils.initUser({ name: "Student Nameynamington" }) @classroom = yield new Classroom({name: 'Classroom', ownerID: @teacher._id, members: [@student1._id, @student2._id] }).save() @emptyClassroom = yield new Classroom({name: 'Empty Classroom', ownerID: @teacher._id, members: [] }).save() done() it 'does not work if you are not the owner of the classroom', utils.wrap (done) -> yield utils.loginUser(@student1) [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions"), { json: true } expect(res.statusCode).toBe(403) done() it 'does not work if you are not logged in', utils.wrap (done) -> [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/member-sessions"), { json: true } expect(res.statusCode).toBe(401) done() it 'works on an empty classroom', utils.wrap (done) -> yield utils.loginUser(@teacher) [res, body] = yield request.getAsync getURL("/db/classroom/#{@emptyClassroom.id}/members?name=true&email=true"), { json: true } expect(res.statusCode).toBe(200) expect(body).toEqual([]) done() it 'returns all members with name and email', utils.wrap (done) -> yield utils.loginUser(@teacher) [res, body] = yield request.getAsync getURL("/db/classroom/#{@classroom.id}/members?name=true&email=true"), { json: true } expect(res.statusCode).toBe(200) expect(body.length).toBe(2) for user in body expect(user.name).toBeDefined() expect(user.email).toBeDefined() expect(user.passwordHash).toBeUndefined() done() describe 'POST /db/classroom/:classroomID/members/:memberID/reset-password', -> it 'changes the password', utils.wrap (done) -> yield utils.clearModels([User, Classroom]) teacher = yield utils.initUser() yield utils.loginUser(teacher) student = yield utils.initUser({ name: "Firstname Lastname" }) newPassword = "this is a new password" classroom = yield new Classroom({name: 'Classroom', ownerID: teacher._id, members: [student._id] }).save() expect(student.get('passwordHash')).not.toEqual(User.hashPassword(newPassword)) [res, body] = yield request.postAsync({ uri: getURL("/db/classroom/#{classroom.id}/members/#{student.id}/reset-password") json: { password: newPassword } }) expect(res.statusCode).toBe(200) changedStudent = yield User.findById(student.id) expect(changedStudent.get('passwordHash')).toEqual(User.hashPassword(newPassword)) done() it "doesn't change the password if you're not their teacher", utils.wrap (done) -> yield utils.clearModels([User, Classroom]) teacher = yield utils.initUser() yield utils.loginUser(teacher) student = yield utils.initUser({ name: "Firstname Lastname" }) student2 = yield utils.initUser({ name: "Firstname Lastname 2" }) newPassword = "this is a new password" classroom = yield new Classroom({name: 'Classroom', ownerID: teacher._id, members: [student2._id] }).save() expect(student.get('passwordHash')).not.toEqual(User.hashPassword(newPassword)) [res, body] = yield request.postAsync({ uri: getURL("/db/classroom/#{classroom.id}/members/#{student.id}/reset-password") json: { password: newPassword } }) expect(res.statusCode).toBe(403) changedStudent = yield User.findById(student.id) expect(changedStudent.get('passwordHash')).toEqual(student.get('passwordHash')) done() it "doesn't change the password if their email is verified", utils.wrap (done) -> yield utils.clearModels([User, Classroom]) teacher = yield utils.initUser() yield utils.loginUser(teacher) student = yield utils.initUser({ name: "Firstname Lastname", emailVerified: true }) newPassword = "this is a new password" classroom = yield new Classroom({name: 'Classroom', ownerID: teacher._id, members: [student._id] }).save() expect(student.get('passwordHash')).not.toEqual(User.hashPassword(newPassword)) [res, body] = yield request.postAsync({ uri: getURL("/db/classroom/#{classroom.id}/members/#{student.id}/reset-password") json: { password: newPassword } }) expect(res.statusCode).toBe(403) changedStudent = yield User.findById(student.id) expect(changedStudent.get('passwordHash')).toEqual(student.get('passwordHash')) done() it "doesn't let you set a 1-character password", utils.wrap (done) -> yield utils.clearModels([User, Classroom]) teacher = yield utils.initUser() yield utils.loginUser(teacher) student = yield utils.initUser({ name: "Firstname Lastname" }) newPassword = "e" classroom = yield new Classroom({name: 'Classroom', ownerID: teacher._id, members: [student._id] }).save() expect(student.get('passwordHash')).not.toEqual(User.hashPassword(newPassword)) [res, body] = yield request.postAsync({ uri: getURL("/db/classroom/#{classroom.id}/members/#{student.id}/reset-password") json: { password: newPassword } }) expect(res.statusCode).toBe(422) changedStudent = yield User.findById(student.id) expect(changedStudent.get('passwordHash')).toEqual(student.get('passwordHash')) done() describe 'GET /db/classroom/:handle/update-courses', -> it 'updates the courses property for that classroom', utils.wrap (done) -> yield utils.clearModels [User, Classroom, Course, Level, Campaign] admin = yield utils.initAdmin() teacher = yield utils.initUser({role: 'teacher'}) # make a single course yield utils.loginUser(admin) yield utils.makeCourse({releasePhase: 'released'}, {campaign: yield utils.makeCampaign()}) # make a classroom, make sure it has the one course yield utils.loginUser(teacher) data = { name: 'Classroom 2' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(1) # make a second course yield utils.loginUser(admin) yield utils.makeCourse({releasePhase: 'released'}, {campaign: yield utils.makeCampaign()}) # make sure classroom still has one course classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(1) # update, check update happens yield utils.loginUser(teacher) [res, body] = yield request.postAsync { uri: classroomsURL + "/#{classroom.id}/update-courses", json: true } expect(body.courses.length).toBe(2) classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(2) done() it 'allows admins to also update a classroom, but uses the owner\'s admin status', utils.wrap (done) -> yield utils.clearModels [User, Classroom, Course, Level, Campaign] admin = yield utils.initAdmin() teacher = yield utils.initUser({role: 'teacher'}) # make two courses, one released, one beta yield utils.loginUser(admin) yield utils.makeCourse({releasePhase: 'released'}, {campaign: yield utils.makeCampaign()}) yield utils.makeCourse({releasePhase: 'beta'}, {campaign: yield utils.makeCampaign()}) # make a classroom, make sure it has the one course yield utils.loginUser(teacher) data = { name: 'Classroom 2' } [res, body] = yield request.postAsync {uri: classroomsURL, json: data } classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(1) # make another released course yield utils.loginUser(admin) yield utils.makeCourse({releasePhase: 'released'}, {campaign: yield utils.makeCampaign()}) # make sure classroom still has one course classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(1) # update, check that classroom has the two released courses [res, body] = yield request.postAsync { uri: classroomsURL + "/#{classroom.id}/update-courses", json: true } expect(body.courses.length).toBe(2) classroom = yield Classroom.findById(res.body._id) expect(classroom.get('courses').length).toBe(2) done()