mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-31 07:12:49 -04:00
Fix teacher sessionless play; uses default campaign levels
Fix typo Fix race condition with loading next level Return an empty object for next level instead of an error; Supermodel has a race condition when some of the models fail to load, when we override an error response as "success". Fix next level spec Remove comment per Scott's request
This commit is contained in:
parent
135f7f05ad
commit
91fa467251
9 changed files with 72 additions and 14 deletions
app
server
spec/server/functional
|
@ -82,9 +82,10 @@ module.exports = class Classroom extends CocoModel
|
|||
return stats
|
||||
|
||||
fetchForCourseInstance: (courseInstanceID, options={}) ->
|
||||
return unless courseInstanceID
|
||||
CourseInstance = require 'models/CourseInstance'
|
||||
courseInstance = if _.isString(courseInstanceID) then new CourseInstance({_id:courseInstanceID}) else courseInstanceID
|
||||
options = _.extend(options, {
|
||||
url: _.result(courseInstance, 'url') + '/classroom'
|
||||
})
|
||||
@fetch(options)
|
||||
@fetch(options)
|
||||
|
|
|
@ -252,6 +252,9 @@ module.exports = class Level extends CocoModel
|
|||
isLadder: ->
|
||||
return @get('type')?.indexOf('ladder') > -1
|
||||
|
||||
fetchNextForCourse: (levelOriginalID, courseInstanceID, options={}) ->
|
||||
options.url = "/db/course_instance/#{courseInstanceID}/levels/#{levelOriginalID}/next"
|
||||
@fetch(options)
|
||||
fetchNextForCourse: ({ levelOriginalID, courseInstanceID, courseID }, options={}) ->
|
||||
if courseInstanceID
|
||||
options.url = "/db/course_instance/#{courseInstanceID}/levels/#{levelOriginalID}/next"
|
||||
else
|
||||
options.url = "/db/course/#{courseID}/levels/#{levelOriginalID}/next"
|
||||
@fetch(options)
|
||||
|
|
|
@ -69,7 +69,7 @@ module.exports = class User extends CocoModel
|
|||
isSessionless: ->
|
||||
# TODO: Fix old users who got mis-tagged as teachers
|
||||
# TODO: Should this just be isTeacher, eventually?
|
||||
me.isTeacher() and utils.getQueryVariable('course', false)
|
||||
Boolean(me.isTeacher() and utils.getQueryVariable('course', false))
|
||||
|
||||
setRole: (role, force=false) ->
|
||||
return if me.isAdmin()
|
||||
|
|
|
@ -29,9 +29,9 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
@newItems = new ThangTypes()
|
||||
@newHeroes = new ThangTypes()
|
||||
|
||||
@classroom = new Classroom()
|
||||
@supermodel.trackRequest(@classroom.fetchForCourseInstance(@courseInstanceID))
|
||||
|
||||
if @courseInstanceID
|
||||
@classroom = new Classroom()
|
||||
@supermodel.trackRequest(@classroom.fetchForCourseInstance(@courseInstanceID))
|
||||
@achievements = options.achievements
|
||||
if not @achievements
|
||||
@achievements = new Achievements()
|
||||
|
@ -43,7 +43,7 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
|
||||
@playSound 'victory'
|
||||
@nextLevel = new Level()
|
||||
@nextLevelRequest = @supermodel.trackRequest @nextLevel.fetchNextForCourse(@level.get('original'), @courseInstanceID)
|
||||
@nextLevelRequest = @supermodel.trackRequest @nextLevel.fetchNextForCourse({ levelOriginalID: @level.get('original'), @courseInstanceID, @courseID })
|
||||
|
||||
@course = options.course
|
||||
if @courseID and not @course
|
||||
|
|
|
@ -96,7 +96,7 @@ module.exports =
|
|||
throw new errors.NotFound('Level original ObjectId not found in Classroom courses')
|
||||
|
||||
if not nextLevelOriginal
|
||||
throw new errors.NotFound('No more levels in that course')
|
||||
res.status(200).send({})
|
||||
|
||||
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
|
||||
dbq.sort({ 'version.major': -1, 'version.minor': -1 })
|
||||
|
@ -122,4 +122,4 @@ module.exports =
|
|||
|
||||
classroom = classroom.toObject({req: req})
|
||||
|
||||
res.status(200).send(classroom)
|
||||
res.status(200).send(classroom)
|
||||
|
|
51
server/middleware/courses.coffee
Normal file
51
server/middleware/courses.coffee
Normal file
|
@ -0,0 +1,51 @@
|
|||
errors = require '../commons/errors'
|
||||
wrap = require 'co-express'
|
||||
database = require '../commons/database'
|
||||
mongoose = require 'mongoose'
|
||||
Campaign = require '../models/Campaign'
|
||||
CourseInstance = require '../models/CourseInstance'
|
||||
Classroom = require '../models/Classroom'
|
||||
Course = require '../models/Course'
|
||||
User = require '../models/User'
|
||||
Level = require '../models/Level'
|
||||
parse = require '../commons/parse'
|
||||
|
||||
module.exports =
|
||||
fetchNextLevel: wrap (req, res) ->
|
||||
levelOriginal = req.params.levelOriginal
|
||||
if not database.isID(levelOriginal)
|
||||
throw new errors.UnprocessableEntity('Invalid level original ObjectId')
|
||||
|
||||
course = yield database.getDocFromHandle(req, Course)
|
||||
if not course
|
||||
throw new errors.NotFound('Course Instance not found.')
|
||||
|
||||
campaign = yield Campaign.findById course.get('campaignID')
|
||||
if not campaign
|
||||
throw new errors.NotFound('Campaign not found.')
|
||||
|
||||
levels = _.values(campaign.get('levels'))
|
||||
levels = _.sortBy(levels, 'campaignIndex')
|
||||
|
||||
nextLevelOriginal = null
|
||||
foundLevelOriginal = false
|
||||
for level, index in levels
|
||||
if level.original.toString() is levelOriginal
|
||||
foundLevelOriginal = true
|
||||
nextLevelOriginal = levels[index+1]?.original
|
||||
break
|
||||
|
||||
if not foundLevelOriginal
|
||||
throw new errors.NotFound('Level original ObjectId not found in that course')
|
||||
|
||||
if not nextLevelOriginal
|
||||
res.status(200).send({})
|
||||
|
||||
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
|
||||
|
||||
|
||||
dbq.sort({ 'version.major': -1, 'version.minor': -1 })
|
||||
dbq.select(parse.getProjectFromReq(req))
|
||||
level = yield dbq
|
||||
level = level.toObject({req: req})
|
||||
res.status(200).send(level)
|
|
@ -5,6 +5,7 @@ module.exports =
|
|||
campaigns: require './campaigns'
|
||||
codelogs: require './codelogs'
|
||||
courseInstances: require './course-instances'
|
||||
courses: require './courses'
|
||||
files: require './files'
|
||||
named: require './named'
|
||||
patchable: require './patchable'
|
||||
|
|
|
@ -59,6 +59,7 @@ module.exports.setup = (app) ->
|
|||
Course = require '../models/Course'
|
||||
app.get('/db/course', mw.rest.get(Course))
|
||||
app.get('/db/course/:handle', mw.rest.getByHandle(Course))
|
||||
app.get('/db/course/:handle/levels/:levelOriginal/next', mw.courses.fetchNextLevel)
|
||||
|
||||
app.get('/db/course_instance/:handle/levels/:levelOriginal/next', mw.courseInstances.fetchNextLevel)
|
||||
app.post('/db/course_instance/:handle/members', mw.auth.checkLoggedIn(), mw.courseInstances.addMembers)
|
||||
|
|
|
@ -315,9 +315,10 @@ describe 'GET /db/course_instance/:handle/levels/:levelOriginal/next', ->
|
|||
expect(res.body.original).toBe(@levelB.original.toString())
|
||||
done()
|
||||
|
||||
it 'returns 404 if the given level is the last level in its course', utils.wrap (done) ->
|
||||
it 'returns empty object if the given level is the last level in its course', utils.wrap (done) ->
|
||||
[res, body] = yield request.getAsync { uri: utils.getURL("/db/course_instance/#{@courseInstanceA.id}/levels/#{@levelB.id}/next"), json: true }
|
||||
expect(res.statusCode).toBe(404)
|
||||
expect(res.statusCode).toBe(200)
|
||||
expect(res.body).toEqual({})
|
||||
done()
|
||||
|
||||
it 'returns 404 if the given level is not in the course instance\'s course', utils.wrap (done) ->
|
||||
|
@ -363,4 +364,4 @@ describe 'GET /db/course_instance/:handle/classroom', ->
|
|||
yield utils.loginUser @user
|
||||
[res, body] = yield request.getAsync(@url, {json: true})
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
done()
|
||||
|
|
Loading…
Add table
Reference in a new issue