2022-06-13 07:42:26 -07:00
import { Meteor } from 'meteor/meteor' ;
import { Mongo } from 'meteor/mongo' ;
import { check } from 'meteor/check' ;
import { Sites } from "./sites" ;
2022-06-20 08:24:35 -07:00
import { Roles } from 'meteor/alanning:roles' ;
2022-07-23 23:42:23 -07:00
import { parse } from 'csv-parse' ;
2022-06-13 07:42:26 -07:00
export const Students = new Mongo . Collection ( 'students' ) ;
if ( Meteor . isServer ) {
2022-06-20 08:24:35 -07:00
Students . createIndex ( { id : 1 } , { name : "External ID" , unique : true } ) ;
2022-06-13 07:42:26 -07:00
// This code only runs on the server
Meteor . publish ( 'students' , function ( siteId ) {
return Students . find ( { siteId } ) ;
} ) ;
}
Meteor . methods ( {
2022-06-20 08:24:35 -07:00
/ * *
* 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 } } ) ;
}
} ,
2022-06-13 07:42:26 -07:00
/ * *
2022-07-23 23:42:23 -07:00
* 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 .
*
2022-06-13 07:42:26 -07:00
* 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
*
2022-07-23 23:42:23 -07:00
* 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]; ` .
2022-06-13 07:42:26 -07:00
* 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
2022-07-23 23:42:23 -07:00
* Student ID , Email , First Name , Last Name , Grade , ( opt ) First Name Alias
* @ type : Currently only supports 'CSV' or 'Aeries Text Report'
2022-06-13 07:42:26 -07:00
* /
2022-07-23 23:42:23 -07:00
'students.loadCsv' ( csv , type , siteId ) {
2022-06-13 07:42:26 -07:00
if ( Roles . userIsInRole ( Meteor . userId ( ) , "admin" , { anyScope : true } ) ) {
check ( csv , String ) ;
check ( siteId , String ) ;
2022-06-20 08:24:35 -07:00
let site = Sites . findOne ( { _id : siteId } ) ;
2022-06-13 07:42:26 -07:00
if ( site ) {
2022-07-23 23:42:23 -07:00
let cleanCsv ;
2022-06-13 07:42:26 -07:00
let lines = csv . split ( /\r?\n/ ) ;
2022-07-23 23:42:23 -07:00
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).
2022-06-13 07:42:26 -07:00
2022-07-23 23:42:23 -07:00
// Remove headers from the CSV.
for ( const line of lines ) {
2022-06-13 07:42:26 -07:00
if ( skip > 0 ) skip -- ;
2022-07-23 23:42:23 -07:00
else if ( pageHeader && line === pageHeader ) {
2022-06-13 07:42:26 -07:00
skip = 2 ;
} else {
2022-07-23 23:42:23 -07:00
if ( ! cleanCsv ) cleanCsv = "" ;
else cleanCsv += '\r\n' ;
cleanCsv += line ;
}
}
//console.log(cleanCsv);
2022-06-13 07:42:26 -07:00
2022-07-23 23:42:23 -07:00
// 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 ;
2022-06-20 08:24:35 -07:00
2022-07-23 23:42:23 -07:00
if ( values . length > 5 ) firstNameAlias = values [ 5 ] ;
2022-06-13 07:42:26 -07:00
2022-07-23 23:42:23 -07:00
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 ) ;
2022-06-13 07:42:26 -07:00
}
}
}
} ) ;