1
0
mirror of https://github.com/matt-fidd/stratos.git synced 2026-01-01 19:59:27 +00:00
Files
stratos/lib/Test.js

219 lines
3.6 KiB
JavaScript

'use strict';
const { EmailBuilder, Emailer } = require('./Emailer');
const TestResult = require('./TestResult');
/**
* A class that represents the date of a test
*/
class TestDate extends Date {
/**
* Overwrite the default string casting implementation to format
* all dates in the British format
*
* @returns {string} The formatted date
*/
toString() {
return this.toLocaleDateString('en-GB');
}
}
class Test {
/**
* The id of the test
* @type {string}
*/
id;
/**
* The id of the test template it is based on
* @type {string}
*/
templateId;
/**
* The test template object that it is based on
* @type {TestTemplate}
*/
template;
/**
* The id of the class it is assigned to
* @type {string}
*/
classId;
/**
* The class object that it is assigned to
* @type {Class}
*/
class;
/**
* The test date in epoch seconds
* @type {number}
*/
epochDate;
/**
* The test date
* @type {TestDate}
*/
date;
#conn;
/**
* @param {string} testId - The id of the test to fetch
*/
constructor(conn, testId) {
this.#conn = conn;
const sql = `
select
testId as id,
testTemplateId as templateId,
classId,
UNIX_TIMESTAMP(testDate) as epochDate
from
test
where
testId = ?;
`;
return (async () => {
const record = await this.#conn.runQuery(sql, [
testId
]);
if (!record.length)
throw new Error('No test found');
for (const [ k, v ] of Object.entries(record[0]))
this[k] = v;
this.date = new TestDate(this.epochDate * 1000);
const [ template, c ] = await Promise.all([
this.getTestTemplate(),
this.getClass()
]);
this.template = template;
this.class = c;
return this;
})();
}
getClass() {
return new (require('./Class'))(this.#conn, this.classId);
}
getTestTemplate() {
return new (require('./TestTemplate'))(
this.#conn,
this.templateId
);
}
getDateString(long = true) {
const options = {
timeZone: 'Europe/London',
day: 'numeric',
month: 'numeric',
year: 'numeric'
};
if (long)
options.weekday = 'long';
return this.date.toLocaleDateString('en-GB', options);
}
async getTestResults() {
const sql = `
select
testResultId
from
testResult
where
testId = ?;
`;
const records = await this.#conn.runQuery(sql, [ this.id ]);
return Promise.all(records.map(r => {
return new (require('./TestResult'))(
this.#conn,
r.testResultId
);
}));
}
async getAverageScore() {
const trs = await this.getTestResults();
return trs.reduce((a, b) => a + b.mark, 0) /
(trs.length || 1);
}
async getAveragePercentage() {
return await this.getAverageScore() /
this.template.maxMark *
100;
}
async addResult(accountId, studentId, mark) {
const tr = await TestResult.create(
this.#conn,
this.id,
accountId,
studentId,
mark
);
const email = new EmailBuilder()
.addTo([ tr.student.getEmail() ])
.setSubject('Stratos - Test result added')
.setBody(
'Your result has been added for ' +
`the test "${this.template.name}" that you ` +
`took on ${this.getDateString()}\n\n` +
`You scored ${mark}/${this.template.maxMark} ` +
`(${tr.percentage}%) which is a grade ` +
`${tr.grade}`
);
const emailer = new Emailer();
await emailer.sendEmail(email);
return tr;
}
async delete() {
const sql = `
delete from
test
where
testId = ?;
`;
try {
await this.#conn.runQuery(sql, [ this.id ]);
} catch (e) {
console.error(e);
}
}
async hasAccess(u) {
const userTests = await u.getTests();
return userTests.filter(t => {
return t.id === this.id;
}).length;
}
}
module.exports = Test;