Finished the first cut of adding asset assignments; Added a page to display asset assignments (need to allow removing them).

This commit is contained in:
2022-08-02 12:02:56 -07:00
parent bd88818428
commit 4560d7203d
7 changed files with 316 additions and 160 deletions

View File

@@ -14,149 +14,150 @@ if (Meteor.isServer) {
Meteor.publish('students', function(siteId) {
return Students.find({siteId});
});
}
Meteor.methods({
async 'students.getPossibleGrades'() {
return Students.rawCollection().distinct('grade', {});
},
/**
* Sets a first name alias that can be overridden by the one that is imported.
* @param _id The student's database ID.
* @param alias The alias to set for the student.
*/
'students.setAlias'(_id, alias) {
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
check(_id, String);
check(alias, String);
Meteor.methods({
'students.getPossibleGrades'() {
return Students.rawCollection().distinct('grade', {});
},
/**
* Sets a first name alias that can be overridden by the one that is imported.
* @param _id The student's database ID.
* @param alias The alias to set for the student.
*/
'students.setAlias'(_id, alias) {
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
check(_id, String);
check(alias, String);
Students.update({_id}, !alias || !alias.length() ? {$unset: {alias: true}} : {$set: {alias}});
}
},
/**
* Assumes that the ID field is a unique ID that never changes for a student.
* This must be true in order for duplicate students to be avoided.
* Will automatically update a student's data, including the site he/she is associated with.
*
* Expects the CSV string to contain comma delimited data in the form:
* email, student ID, first name, last name, grade, first name alias, last name alias
*
* The query in Aeries is: `LIST STU ID SEM FN LN NG FNA`.
* A more complete Aeries query: `LIST STU STU.ID STU.SEM STU.FN STU.LN STU.NG BY STU.NG STU.SEM IF STU.NG >= 7 AND NG <= 12 AND STU.NS = 5`
* Note that FNA (First Name Alias) is optional.
* Note that you might want to include a school ID in the IF if you have multiple schools in the district.
* The query in SQL is: `SELECT [STU].[ID] AS [Student ID], [STU].[SEM] AS [StuEmail], STU.FN AS [First Name], STU.LN AS [Last Name], [STU].[GR] AS [Grade], [STU].[FNA] AS [First Name Alias], [STU].[LNA] AS [Last Name Alias] FROM (SELECT [STU].* FROM STU WHERE [STU].DEL = 0) STU WHERE ( [STU].SC = 5) ORDER BY [STU].[LN], [STU].[FN];`.
* Run the query in Aeries as a `Report`, select TXT, and upload here.
*
* Aeries adds a header per 'page' of data (I think 35 entries per page).
* Example:
* Anderson Valley Jr/Sr High School,6/11/2022
* 2021-2022,Page 1
* Student ID, Email, First Name,Last Name,Grade,(opt) First Name Alias
* @type: Currently only supports 'CSV' or 'Aeries Text Report'
*/
'students.loadCsv'(csv, type, siteId) {
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
check(csv, String);
check(siteId, String);
Students.update({_id}, !alias || !alias.length() ? {$unset: {alias: true}} : {$set: {alias}});
}
},
/**
* Assumes that the ID field is a unique ID that never changes for a student.
* This must be true in order for duplicate students to be avoided.
* Will automatically update a student's data, including the site he/she is associated with.
*
* Expects the CSV string to contain comma delimited data in the form:
* email, student ID, first name, last name, grade, first name alias, last name alias
*
* The query in Aeries is: `LIST STU ID SEM FN LN NG FNA`.
* A more complete Aeries query: `LIST STU STU.ID STU.SEM STU.FN STU.LN STU.NG BY STU.NG STU.SEM IF STU.NG >= 7 AND NG <= 12 AND STU.NS = 5`
* Note that FNA (First Name Alias) is optional.
* Note that you might want to include a school ID in the IF if you have multiple schools in the district.
* The query in SQL is: `SELECT [STU].[ID] AS [Student ID], [STU].[SEM] AS [StuEmail], STU.FN AS [First Name], STU.LN AS [Last Name], [STU].[GR] AS [Grade], [STU].[FNA] AS [First Name Alias], [STU].[LNA] AS [Last Name Alias] FROM (SELECT [STU].* FROM STU WHERE [STU].DEL = 0) STU WHERE ( [STU].SC = 5) ORDER BY [STU].[LN], [STU].[FN];`.
* Run the query in Aeries as a `Report`, select TXT, and upload here.
*
* Aeries adds a header per 'page' of data (I think 35 entries per page).
* Example:
* Anderson Valley Jr/Sr High School,6/11/2022
* 2021-2022,Page 1
* Student ID, Email, First Name,Last Name,Grade,(opt) First Name Alias
* @type: Currently only supports 'CSV' or 'Aeries Text Report'
*/
'students.loadCsv'(csv, type, siteId) {
if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) {
check(csv, String);
check(siteId, String);
let site = Sites.findOne({_id: siteId});
let site = Sites.findOne({_id: siteId});
if(site) {
let cleanCsv;
let lines = csv.split(/\r?\n/);
let pageHeader = type === 'Aeries Text Report' ? lines[0] : null; // Skip the repeating header lines for an Aeries text report.
let skip = type === 'CSV' ? 1 : 0; // Skip the first line of a CSV file (headers).
if(site) {
let cleanCsv;
let lines = csv.split(/\r?\n/);
let pageHeader = type === 'Aeries Text Report' ? lines[0] : null; // Skip the repeating header lines for an Aeries text report.
let skip = type === 'CSV' ? 1 : 0; // Skip the first line of a CSV file (headers).
// Remove headers from the CSV.
for(const line of lines) {
if (skip > 0) skip--;
else if (pageHeader && line === pageHeader) {
skip = 2;
} else {
if(!cleanCsv) cleanCsv = "";
else cleanCsv += '\r\n';
cleanCsv += line;
}
}
//console.log(cleanCsv);
// Note: This doesn't work because some values are quoted and contain commas as a value character.
// Parse the CSV (now without any headers).
// lines = cleanCsv.split(/\r\n/);
// for(const line of lines) {
// let values = line.split(/\s*,\s*/);
//
// if(values.length >= 5) {
// let id = values[0];
// let email = values[1];
// let firstName = values[2];
// let lastName = values[3];
// let grade = parseInt(values[4], 10);
// let firstNameAlias = "";
// let active = true;
//
// if(values.length > 5) firstNameAlias = values[5];
//
// let student = {siteId, email, id, firstName, lastName, grade, firstNameAlias, active};
//
// // console.log(student);
// // Update or insert in the db.
// console.log("Upserting: " + student);
// Students.upsert({id}, {$set: student});
// }
// }
const bound = Meteor.bindEnvironment((callback) => {callback();});
parse(cleanCsv, {}, function(err, records) {
bound(() => {
if(err) console.error(err);
else {
let foundIds = new Set();
let duplicates = [];
console.log("Found " + records.length + " records.");
for(const values of records) {
let id = values[0];
let email = values[1];
let firstName = values[2];
let lastName = values[3];
let grade = parseInt(values[4], 10);
let firstNameAlias = "";
let active = true;
if(values.length > 5) firstNameAlias = values[5];
let student = {siteId, email, id, firstName, lastName, grade, firstNameAlias, active};
// Track the student ID's and record duplicates. This is used to ensure our counts are accurate later.
if(foundIds.has(student.id)) {
duplicates.push(student.id);
}
else {
foundIds.add(student.id);
}
//console.log(student);
try {
Students.upsert({id: student.id}, {$set: student});
}
catch(err) {
console.error(err);
}
}
console.log(duplicates.length + " records were duplicates:");
console.log(duplicates);
// Remove headers from the CSV.
for(const line of lines) {
if (skip > 0) skip--;
else if (pageHeader && line === pageHeader) {
skip = 2;
} else {
if(!cleanCsv) cleanCsv = "";
else cleanCsv += '\r\n';
cleanCsv += line;
}
});
})
}
else {
console.log("Failed to find the site with the ID: " + siteId);
}
//console.log(cleanCsv);
// Note: This doesn't work because some values are quoted and contain commas as a value character.
// Parse the CSV (now without any headers).
// lines = cleanCsv.split(/\r\n/);
// for(const line of lines) {
// let values = line.split(/\s*,\s*/);
//
// if(values.length >= 5) {
// let id = values[0];
// let email = values[1];
// let firstName = values[2];
// let lastName = values[3];
// let grade = parseInt(values[4], 10);
// let firstNameAlias = "";
// let active = true;
//
// if(values.length > 5) firstNameAlias = values[5];
//
// let student = {siteId, email, id, firstName, lastName, grade, firstNameAlias, active};
//
// // console.log(student);
// // Update or insert in the db.
// console.log("Upserting: " + student);
// Students.upsert({id}, {$set: student});
// }
// }
const bound = Meteor.bindEnvironment((callback) => {callback();});
parse(cleanCsv, {}, function(err, records) {
bound(() => {
if(err) console.error(err);
else {
let foundIds = new Set();
let duplicates = [];
console.log("Found " + records.length + " records.");
for(const values of records) {
let id = values[0];
let email = values[1];
let firstName = values[2];
let lastName = values[3];
let grade = parseInt(values[4], 10);
let firstNameAlias = "";
let active = true;
if(values.length > 5) firstNameAlias = values[5];
let student = {siteId, email, id, firstName, lastName, grade, firstNameAlias, active};
// Track the student ID's and record duplicates. This is used to ensure our counts are accurate later.
if(foundIds.has(student.id)) {
duplicates.push(student.id);
}
else {
foundIds.add(student.id);
}
//console.log(student);
try {
Students.upsert({id: student.id}, {$set: student});
}
catch(err) {
console.error(err);
}
}
console.log(duplicates.length + " records were duplicates:");
console.log(duplicates);
}
});
})
}
else {
console.log("Failed to find the site with the ID: " + siteId);
}
}
}
}
});
});
}