🐛Fix course ordering and furthest logic in dashboard

Also speeding up server APIs via lean() db calls
This commit is contained in:
Matt Lott 2016-09-19 13:16:47 -07:00
parent 7efccfeac4
commit 951db5a721
5 changed files with 73 additions and 54 deletions

View file

@ -157,6 +157,7 @@ block content
.small Restricted to courses instances from last #{view.furthestCourseDayRangeRecent} days
.small Teacher: owner of a course instance
.small Student: member of a course instance (assigned to course)
.small Only course.releasePhase == 'released'
.small For course instances != Single Player, hourOfCode != true
.small Counts are not summed. I.e. a student or teacher only contributes to the count of one course
.small Paid student: user.coursePrepaid set and prepaid.properties.trialRequestID NOT set
@ -190,7 +191,8 @@ block content
td= row.totals['Free Students'] || 0
td= row.totals['Total Students'] || 0
else
div Loading ...
br
p Loading ...
h3 Furthest Course in last #{view.furthestCourseDayRange} days
if view.courseDistributions
@ -217,7 +219,8 @@ block content
td= row.totals['Free Students'] || 0
td= row.totals['Total Students'] || 0
else
div Loading ...
br
p Loading ...
.school-sales
h3 School Sales
@ -245,7 +248,7 @@ block content
td
td
else
div Loading ...
p Loading ...
#school-counts
h3 School Counts
@ -262,7 +265,7 @@ block content
td= val.schoolName
td= val.count
else
div Loading ...
p Loading ...
h1 Active Users
if view.activeUsers.length > 0

View file

@ -252,14 +252,14 @@ module.exports = class AnalyticsView extends RootView
}, 0).load()
@courses = new CocoCollection([], { url: "/db/course", model: Course})
@courses.comparator = "_id"
@listenToOnce @courses, 'sync', @onCoursesSync
@supermodel.loadCollection(@courses)
onCoursesSync: ->
# Assumes courses retrieved in order
@courses.remove(@courses.findWhere({releasePhase: 'beta'}))
sortedCourses = utils.sortCourses(@courses.models ? [])
@courseOrderMap = {}
@courseOrderMap[@courses.models[i].get('_id')] = i for i in [0...@courses.models.length]
@courseOrderMap[sortedCourses[i].get('_id')] = i for i in [0...sortedCourses.length]
startDay = new Date()
startDay.setUTCDate(startDay.getUTCDate() - @furthestCourseDayRange)
@ -291,6 +291,9 @@ module.exports = class AnalyticsView extends RootView
for courseInstance in data.courseInstances
continue if utils.objectIdToDate(courseInstance._id) < startDate
courseID = courseInstance.courseID
unless @courseOrderMap[courseID]?
console.error "ERROR: no course order for courseID=#{courseID}"
continue
teacherID = courseInstance.ownerID
for studentID in courseInstance.members
studentPaidStatusMap[studentID] = 'free'
@ -303,7 +306,7 @@ module.exports = class AnalyticsView extends RootView
prepaidUserMap = {}
for user in data.students
continue unless studentPaidStatusMap[user._id]
if prepaidID = user.coursePrepaidID or user.coursePrepaid?._id
if prepaidID = user.coursePrepaid?._id
studentPaidStatusMap[user._id] = 'paid'
prepaidUserMap[prepaidID] ?= []
prepaidUserMap[prepaidID].push(user._id)
@ -324,17 +327,27 @@ module.exports = class AnalyticsView extends RootView
teacherPaidStatusMap = {}
for teacher, students of teacherStudentsMap
for student in students
unless studentFurthestCourseMap[student]?
console.error "ERROR: no student furthest map for teacher=#{teacher} student=#{student}"
continue
if not teacherPaidStatusMap[teacher]
teacherPaidStatusMap[teacher] = studentPaidStatusMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if teacherPaidStatusMap[teacher] is 'trial' and studentPaidStatusMap[student] is 'paid'
teacherPaidStatusMap[teacher] = studentPaidStatusMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if teacherPaidStatusMap[teacher] is 'free' and studentPaidStatusMap[student] in ['paid', 'trial']
teacherPaidStatusMap[teacher] = studentPaidStatusMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if teacherFurthestCourseMap[teacher] < studentFurthestCourseMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if teacherPaidStatusMap[teacher] is 'paid'
if studentPaidStatusMap[student] is 'paid' and teacherFurthestCourseMap[teacher] < studentFurthestCourseMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if teacherPaidStatusMap[teacher] is 'trial'
if studentPaidStatusMap[student] is 'paid'
teacherPaidStatusMap[teacher] = studentPaidStatusMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if studentPaidStatusMap[student] is 'trial' and teacherFurthestCourseMap[teacher] < studentFurthestCourseMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else # free teacher
if studentPaidStatusMap[student] in ['paid', 'trial']
teacherPaidStatusMap[teacher] = studentPaidStatusMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
else if studentPaidStatusMap[student] is 'free' and teacherFurthestCourseMap[teacher] < studentFurthestCourseMap[student]
teacherFurthestCourseMap[teacher] = studentFurthestCourseMap[student]
# Build table of student/teacher paid/trial/free totals
updateCourseTotalsMap = (courseTotalsMap, furthestCourseMap, paidStatusMap, columnSuffix) =>
@ -360,12 +373,12 @@ module.exports = class AnalyticsView extends RootView
courseDistributions = []
for courseName, totals of courseTotalsMap
courseDistributions.push({courseName: courseName, totals: totals})
courseDistributions.sort (a, b) ->
if a.courseName.indexOf('Introduction') >= 0 and b.courseName.indexOf('Introduction') < 0 then return -1
else if b.courseName.indexOf('Introduction') >= 0 and a.courseName.indexOf('Introduction') < 0 then return 1
else if a.courseName.indexOf('All Courses') >= 0 and b.courseName.indexOf('All Courses') < 0 then return 1
courseDistributions.sort (a, b) =>
if a.courseName.indexOf('All Courses') >= 0 and b.courseName.indexOf('All Courses') < 0 then return 1
else if b.courseName.indexOf('All Courses') >= 0 and a.courseName.indexOf('All Courses') < 0 then return -1
a.courseName.localeCompare(b.courseName)
aID = @courses.findWhere({name: a.courseName}).id
bID = @courses.findWhere({name: b.courseName}).id
@courseOrderMap[aID] - @courseOrderMap[bID]
courseDistributions

View file

@ -44,39 +44,41 @@ PaymentHandler = class PaymentHandler extends Handler
payment
getSchoolSalesAPI: (req, res, code) ->
return @sendUnauthorizedError(res) unless req.user?.isAdmin()
userIDs = [];
Payment.find({}, {amount: 1, created: 1, description: 1, prepaidID: 1, productID: 1, purchaser: 1, service: 1}).exec (err, payments) =>
throw new errors.Unauthorized('You must be an administrator.') unless req.user?.isAdmin()
Payment.find({}, {amount: 1, created: 1, description: 1, prepaidID: 1, productID: 1, purchaser: 1, service: 1}).lean().exec (err, payments) =>
return @sendDatabaseError(res, err) if err
userIDs = [];
schoolSales = []
prepaidIDs = []
prepaidPaymentMap = {}
for payment in payments
continue unless payment.get('amount')? and payment.get('amount') > 0
unless created = payment.get('created')
created = payment.get('_id').getTimestamp()
description = payment.get('description') ? ''
if prepaidID = payment.get('prepaidID')
continue unless payment.amount > 0
unless created = payment.created
paymentID = mongoose.Types.ObjectId(payment._id)
created = paymentID.getTimestamp()
description = payment.description ? ''
if prepaidID = payment.prepaidID
unless prepaidPaymentMap[prepaidID.valueOf()]
prepaidPaymentMap[prepaidID.valueOf()] = {_id: payment.get('_id').valueOf(), amount: payment.get('amount'), created: created, description: description, userID: payment.get('purchaser').valueOf(), prepaidID: prepaidID.valueOf()}
prepaidPaymentMap[prepaidID.valueOf()] = {_id: payment._id, amount: payment.amount, created: created, description: description, userID: payment.purchaser, prepaidID: prepaidID}
prepaidIDs.push(prepaidID)
userIDs.push(payment.get('purchaser'))
else if payment.get('productID') is 'custom' or payment.get('service') is 'external' or payment.get('service') is 'invoice'
schoolSales.push({_id: payment.get('_id').valueOf(), amount: payment.get('amount'), created: created, description: description, userID: payment.get('purchaser').valueOf()})
userIDs.push(payment.get('purchaser'))
userIDs.push(payment.purchaser)
else if payment.productID is 'custom' or payment.service is 'external' or payment.service is 'invoice'
schoolSales.push({_id: payment._id, amount: payment.amount, created: created, description: description, userID: payment.purchaser})
userIDs.push(payment.purchaser)
Prepaid.find({$and: [{_id: {$in: prepaidIDs}}, {type: 'course'}]}, {_id: 1}).exec (err, prepaids) =>
Prepaid.find({$and: [{_id: {$in: prepaidIDs}}, {type: 'course'}]}, {_id: 1}).lean().exec (err, prepaids) =>
return @sendDatabaseError(res, err) if err
for prepaid in prepaids
schoolSales.push(prepaidPaymentMap[prepaid.get('_id').valueOf()])
schoolSales.push(prepaidPaymentMap[prepaid._id])
User.find({_id: {$in: userIDs}}).exec (err, users) =>
User.find({_id: {$in: userIDs}}).lean().exec (err, users) =>
return @sendDatabaseError(res, err) if err
userMap = {}
for user in users
userMap[user.get('_id').valueOf()] = user
userMap[user._id] = user
for schoolSale in schoolSales
schoolSale.user = userMap[schoolSale.userID]?.toObject()
schoolSale.user = userMap[schoolSale.userID]
@sendSuccess(res, schoolSales)

View file

@ -477,11 +477,11 @@ UserHandler = class UserHandler extends Handler
{schoolName: {$exists: true}},
{schoolName: {$ne: ''}}
]}
User.find(query, {schoolName: 1}).exec (err, documents) =>
User.find(query, {schoolName: 1}).lean().exec (err, documents) =>
return @sendDatabaseError(res, err) if err
schoolCountMap = {}
for doc in documents
schoolName = doc.get('schoolName')
schoolName = doc.schoolName
schoolCountMap[schoolName] ?= 0;
schoolCountMap[schoolName]++;
schoolCounts = []
@ -489,7 +489,6 @@ UserHandler = class UserHandler extends Handler
continue unless count >= minCount
schoolCounts.push schoolName: schoolName, count: count
@sendSuccess(res, schoolCounts)
agreeToCLA: (req, res) ->
return @sendForbiddenError(res) unless req.user
doc =

View file

@ -155,27 +155,29 @@ module.exports =
fetchRecent: wrap (req, res) ->
query = {$and: [{name: {$ne: 'Single Player'}}, {hourOfCode: {$ne: true}}]}
throw new errors.Unauthorized('You must be an administrator.') unless req.user?.isAdmin()
courses = yield Course.find({releasePhase: 'released'}).select({_id: 1}).lean()
courseIDs = (course._id for course in courses)
query = {$and: [{courseID: {$in: courseIDs}}, {name: {$ne: 'Single Player'}}, {hourOfCode: {$ne: true}}]}
query["$and"].push(_id: {$gte: objectIdFromTimestamp(req.body.startDay + "T00:00:00.000Z")}) if req.body.startDay?
query["$and"].push(_id: {$lt: objectIdFromTimestamp(req.body.endDay + "T00:00:00.000Z")}) if req.body.endDay?
courseInstances = yield CourseInstance.find(query, {courseID: 1, members: 1, ownerID: 1})
courseInstances = yield CourseInstance.find(query, {courseID: 1, members: 1, ownerID: 1}).lean()
userIDs = []
for courseInstance in courseInstances
if members = courseInstance.get('members')
if members = courseInstance.members
userIDs.push(userID) for userID in members
users = yield User.find({_id: {$in: userIDs}}, {coursePrepaid: 1, coursePrepaidID: 1})
users = yield User.find({_id: {$in: userIDs}, coursePrepaid: {$exists: true}}, {coursePrepaid: 1}).lean()
prepaidIDs = []
for user in users
if prepaidID = user.get('coursePrepaid')
prepaidIDs.push(prepaidID._id)
prepaids = yield Prepaid.find({_id: {$in: prepaidIDs}}, {properties: 1})
prepaidIDs = (user.coursePrepaid._id for user in users when user.coursePrepaid)
prepaids = yield Prepaid.find({_id: {$in: prepaidIDs}}, {properties: 1}).lean()
res.send({
courseInstances: (courseInstance.toObject({req: req}) for courseInstance in courseInstances)
students: (user.toObject({req: req}) for user in users)
prepaids: (prepaid.toObject({req: req}) for prepaid in prepaids)
courseInstances: courseInstances
students: users
prepaids: prepaids
})
fetchNonHoc: wrap (req, res) ->