mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-11 16:21:08 -05:00
144 lines
6.9 KiB
CoffeeScript
144 lines
6.9 KiB
CoffeeScript
RootView = require 'views/core/RootView'
|
|
CocoCollection = require 'collections/CocoCollection'
|
|
Classroom = require 'models/Classroom'
|
|
TrialRequest = require 'models/TrialRequest'
|
|
User = require 'models/User'
|
|
|
|
# TODO: trim orphaned students: course instances != Single Player, hourOfCode != true
|
|
# TODO: match anonymous trial requests with real users via email
|
|
|
|
module.exports = class SchoolCountsView extends RootView
|
|
id: 'admin-school-counts-view'
|
|
template: require 'templates/admin/school-counts'
|
|
|
|
initialize: ->
|
|
return super() unless me.isAdmin()
|
|
@classrooms = new CocoCollection([], { url: "/db/classroom/-/users", model: Classroom })
|
|
@supermodel.loadCollection(@classrooms, 'classrooms', {cache: false})
|
|
@students = new CocoCollection([], { url: "/db/user/-/students", model: User })
|
|
@supermodel.loadCollection(@students, 'students', {cache: false})
|
|
@teachers = new CocoCollection([], { url: "/db/user/-/teachers", model: User })
|
|
@supermodel.loadCollection(@teachers, 'teachers', {cache: false})
|
|
@trialRequests = new CocoCollection([], { url: "/db/trial.request/-/users", model: TrialRequest })
|
|
@supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false})
|
|
super()
|
|
|
|
onLoaded: ->
|
|
return super() unless me.isAdmin()
|
|
|
|
console.log(new Date().toISOString(), 'onLoaded')
|
|
|
|
teacherMap = {} # Used to make sure teachers and students only counted once
|
|
studentMap = {} # Used to make sure teachers and students only counted once
|
|
teacherStudentMap = {} # Used to link students to their teacher locations
|
|
orphanedSchoolStudentMap = {} # Used to link student schoolName to teacher Nces data
|
|
countryStateDistrictSchoolCountsMap = {} # Data graph
|
|
|
|
console.log(new Date().toISOString(), 'Processing classrooms...')
|
|
for classroom in @classrooms.models
|
|
teacherID = classroom.get('ownerID')
|
|
teacherMap[teacherID] ?= {}
|
|
teacherMap[teacherID] = true
|
|
teacherStudentMap[teacherID] ?= {}
|
|
for studentID in classroom.get('members')
|
|
studentMap[studentID] = true
|
|
teacherStudentMap[teacherID][studentID] = true
|
|
|
|
console.log(new Date().toISOString(), 'Processing teachers...')
|
|
for teacher in @teachers.models
|
|
teacherMap[teacher.id] ?= {}
|
|
delete studentMap[teacher.id]
|
|
|
|
console.log(new Date().toISOString(), 'Processing students...')
|
|
for student in @students.models when not teacherMap[student.id]
|
|
schoolName = student.get('schoolName')
|
|
studentMap[student.id] = true
|
|
orphanedSchoolStudentMap[schoolName] ?= {}
|
|
orphanedSchoolStudentMap[schoolName][student.id] = true
|
|
|
|
console.log(new Date().toISOString(), 'Processing trial requests...')
|
|
# TODO: this step is crazy slow
|
|
orphanSchoolsMatched = 0
|
|
orphanStudentsMatched = 0
|
|
for trialRequest in @trialRequests.models
|
|
teacherID = trialRequest.get('applicant')
|
|
unless teacherMap[teacherID]
|
|
# console.log("Skipping non-teacher #{teacherID} trial request #{trialRequest.id}")
|
|
continue
|
|
props = trialRequest.get('properties')
|
|
if props.nces_id and props.country and props.state
|
|
country = props.country
|
|
state = props.state
|
|
district = props.nces_district
|
|
school = props.nces_name
|
|
countryStateDistrictSchoolCountsMap[country] ?= {}
|
|
countryStateDistrictSchoolCountsMap[country][state] ?= {}
|
|
countryStateDistrictSchoolCountsMap[country][state][district] ?= {}
|
|
countryStateDistrictSchoolCountsMap[country][state][district][school] ?= {students: {}, teachers: {}}
|
|
countryStateDistrictSchoolCountsMap[country][state][district][school].teachers[teacherID] = true
|
|
for studentID, val of teacherStudentMap[teacherID]
|
|
countryStateDistrictSchoolCountsMap[country][state][district][school].students[studentID] = true
|
|
for orphanSchool, students of orphanedSchoolStudentMap
|
|
if school is orphanSchool or school.replace(/unified|elementary|high|district|#\d+|isd|unified district|school district/ig, '').trim() is orphanSchool.trim()
|
|
orphanSchoolsMatched++
|
|
for studentID, val of students
|
|
orphanStudentsMatched++
|
|
countryStateDistrictSchoolCountsMap[country][state][district][school].students[studentID] = true
|
|
delete orphanedSchoolStudentMap[school]
|
|
console.log(new Date().toISOString(), "#{orphanSchoolsMatched} orphanSchoolsMatched #{orphanStudentsMatched} orphanStudentsMatched")
|
|
|
|
console.log(new Date().toISOString(), 'Building graph...')
|
|
@totalSchools = 0
|
|
@totalStudents = 0
|
|
@totalTeachers = 0
|
|
@totalStates = 0
|
|
@stateCounts = []
|
|
stateCountsMap = {}
|
|
@districtCounts = []
|
|
for country, stateDistrictSchoolCountsMap of countryStateDistrictSchoolCountsMap
|
|
continue unless /usa/ig.test(country)
|
|
for state, districtSchoolCountsMap of stateDistrictSchoolCountsMap
|
|
@totalStates++
|
|
stateData = {state: state, districts: 0, schools: 0, students: 0, teachers: 0}
|
|
for district, schoolCountsMap of districtSchoolCountsMap
|
|
stateData.districts++
|
|
districtData = {state: state, district: district, schools: 0, students: 0, teachers: 0}
|
|
for school, counts of schoolCountsMap
|
|
studentCount = Object.keys(counts.students).length
|
|
teacherCount = Object.keys(counts.teachers).length
|
|
@totalSchools++
|
|
@totalStudents += studentCount
|
|
@totalTeachers += teacherCount
|
|
stateData.schools++
|
|
stateData.students += studentCount
|
|
stateData.teachers += teacherCount
|
|
districtData.schools++
|
|
districtData.students += studentCount
|
|
districtData.teachers += teacherCount
|
|
@districtCounts.push(districtData)
|
|
@stateCounts.push(stateData)
|
|
stateCountsMap[state] = stateData
|
|
@untriagedStudents = Object.keys(studentMap).length - @totalStudents
|
|
|
|
@stateCounts.sort (a, b) ->
|
|
return -1 if a.students > b.students
|
|
return 1 if a.students < b.students
|
|
return -1 if a.teachers > b.teachers
|
|
return 1 if a.teachers < b.teachers
|
|
return -1 if a.districts > b.districts
|
|
return 1 if a.districts < b.districts
|
|
b.state.localeCompare(a.state)
|
|
@districtCounts.sort (a, b) ->
|
|
if a.state isnt b.state
|
|
return -1 if stateCountsMap[a.state].students > stateCountsMap[b.state].students
|
|
return 1 if stateCountsMap[a.state].students < stateCountsMap[b.state].students
|
|
return -1 if stateCountsMap[a.state].teachers > stateCountsMap[b.state].teachers
|
|
return 1 if stateCountsMap[a.state].teachers < stateCountsMap[b.state].teachers
|
|
a.state.localeCompare(b.state)
|
|
else
|
|
return -1 if a.students > b.students
|
|
return 1 if a.students < b.students
|
|
return -1 if a.teachers > b.teachers
|
|
return 1 if a.teachers < b.teachers
|
|
a.district.localeCompare(b.district)
|
|
super()
|