quizzer
Version:
Quizzer is a webserver for collaborative writing lab support. Based on a _fail early, fail often? approach to written language, the tool is particularly suited to second-language learners. The workflow (essay - error - quiz - exam) treats mistakes as an o
152 lines (143 loc) • 6.34 kB
JavaScript
(function () {
var cogClass = function () {};
cogClass.prototype.exec = function (params, request, response) {
var oops = this.utils.apiError;
var adminID = params.adminid;
var classID = params.classid;
var sys = this.sys;
var utf8 = this.sys.utf8;
var retObj = {
className:'',
studentCount:0,
examIDs:[],
examIDmap:{},
sheet:[[]]
};
beginTransaction();
// Calls
// * Get class name
// * Get list of students
// * Get list of exams
// * For each student/exam, get list of results
function beginTransaction () {
sys.db.run("BEGIN TRANSACTION",function(err){
if (err) {return oops(response,err,'class/downloadcsv(0)')};
getClassName();
});
}
function getClassName () {
var sql = 'SELECT name FROM classes WHERE classID=?;'
sys.db.get(sql,[classID],function(err,row){
if (err||!row) {return oops(response,err,'class/downloadcsv(1)')};
retObj.className = row.name;
getStudents();
});
}
function getStudents () {
var sql = 'SELECT students.studentID,students.name,email '
+ 'FROM memberships '
+ 'JOIN students USING(studentID) '
+ 'WHERE memberships.classID=? AND (privacy IS NULL OR privacy=0) '
+ 'ORDER BY students.studentID;'
sys.db.all(sql,[classID],function(err,rows){
if (err) {return oops(response,err,'class/downloadcsv(2)')};
retObj.sheet[0].push('Student ID');
retObj.sheet[0].push('Name');
retObj.sheet[0].push('Email');
if (rows) {
retObj.studentCount = rows.length;
for (var i=0,ilen=rows.length;i<ilen;i+=1) {
var row = rows[i];
var sheetrow = [
row.studentID,
row.name,
row.email
];
retObj.sheet.push(sheetrow);
}
getExams();
} else {
endTransaction();
}
});
};
function getExams() {
var sql = 'SELECT quizID,examName '
+ 'FROM quizzes '
+ 'WHERE classID=? AND examName IS NOT NULL '
+ 'ORDER BY quizNumber;'
sys.db.all(sql,[classID],function(err,rows){
if (err) {return oops(response,err,'class/downloadcsv(3)')};
if (rows) {
for (var i=0,ilen=rows.length;i<ilen;i+=1) {
var row = rows[i];
retObj.examIDmap[row.quizID] = retObj.sheet[0].length;
retObj.sheet[0].push(row.examName);
retObj.examIDs.push(row.quizID);
}
getStudentResults(0,retObj.examIDs.length);
} else {
endTransaction();
}
});
};
function getStudentResults(pos,limit) {
if (pos === limit) {
endTransaction();
return;
}
// This is a little tricky, since the number and alignment of students
// must match the list kicked out in the getStudents() function above.
var sql = 'SELECT memberships.studentID,'
+ 'CASE WHEN counts.numberOfAnswers IS NOT NULL THEN counts.numberOfAnswers ELSE \'\' END AS numberOfAnswers,'
+ 'CASE WHEN counts.numberCorrect IS NOT NULL THEN counts.numberCorrect ELSE \'\' END AS numberCorrect '
+ 'FROM memberships '
+ 'JOIN students USING(studentID) '
+ 'LEFT JOIN ('
+ 'SELECT answers.studentID,'
+ 'COUNT(answers.answerID) AS numberOfAnswers,'
+ 'COUNT(correct.answerID) AS numberCorrect '
+ 'FROM questions '
+ 'LEFT JOIN answers ON answers.questionID=questions.questionID '
+ 'LEFT JOIN answers AS correct ON correct.answerID=answers.answerID AND answers.choice=questions.correct '
+ 'WHERE questions.quizID=? '
+ 'GROUP BY answers.studentID '
+ 'ORDER BY answers.studentID'
+ ') AS counts ON counts.studentID=memberships.studentID '
+ 'WHERE memberships.classID=? AND (privacy IS NULL OR privacy=0) '
+ 'ORDER BY memberships.studentID;'
var quizID = retObj.examIDs[pos];
sys.db.all(sql,[quizID,classID],function(err,rows){
if (err) {return oops(response,err,'class/downloadcsv(4)')};
if (rows) {
var colpos = retObj.examIDmap[quizID];
for (var i=0,ilen=rows.length;i<ilen;i+=1) {
var row = rows[i];
retObj.sheet[i+1][colpos] = row.numberCorrect;
}
}
getStudentResults(pos+1,limit);
});
}
function endTransaction () {
sys.db.run("END TRANSACTION",function(err){
if (err) {return oops(response,err,'class/downloadcsv(5)')};
finishDownload();
});
}
function finishDownload() {
var sheet = retObj.sheet;
for (var i=0,ilen=retObj.sheet.length;i<ilen;i+=1) {
var row = sheet[i];
for (var j=0,jlen=row.length;j<jlen;j+=1) {
var cell = row[j];
row[j] = ('' + row[j]).replace('"','\\"');
}
row = '"' + row.join('","') + '"';
};
response.writeHead(200, {'Content-Type': 'text/csv','Content-Disposition':'attachment; filename="' + utf8.encode(retObj.className) + ' (roster).csv"'});
response.end(retObj.sheet.join('\n'));
}
}
exports.cogClass = cogClass;
})();