Source: process-midterm-eval.js


var DEBUG = false;



var MY_SERVICE_KEY = 'midterm_eval';
// identifies our service within the services_config.json file




// javascript app to connect to firebase and email pdf

// dependencies
require('rconsole');
var Firebase = require("firebase");
var fs = require('fs');
var mustache = require('mustache');

var transactq = require(__dirname + '/transactq');


console.set({
    title: 'gradphile.process-midterm-eval'
});






//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

// load common and secret values for all services

var config = require(__dirname + '/configure_microservice');

config.loadConfiguration(MY_SERVICE_KEY);


//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------


if (DEBUG) {
    config.cc_email = "tom+test@houptlab.org";
    config.bcc_email = "tom+test@houptlab.org";
}

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

// set up transactq

transactq.set_firebase_config(MY_SERVICE_KEY,
    config.firebase_base_url,
    config.firebaseSecret);

transactq.set_mail_server(config.email_account['server'],
    config.email_account['from'],
    config.email_account['username'],
    config.email_account['password']);


//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
// Load template files

var template_names = [
    "instructor_confirmation_email_template",
    "student_reminder_email_template",
    "student_confirmation_email_template",
    "assoc_chair_confirmation_email_template"

];

var templates = {};

for (var i = 0; i < template_names.length; i++) {
    templates[template_names[i]] = fs.readFileSync(__dirname + '/email_templates/midterm_eval/' + template_names[i] + '.txt', {
        encoding: 'utf-8'
    });
    mustache.parse(templates[template_names[i]]);
}



//---------------------------------------------------------------------------------------

/**

return a hashmap, eg.
{ "year": "2021", term: "fall"}

Note strings, lowercase.

*/

function current_term(offset_in_terms) {

     let curr_date = new Date();
     let curr_year =  curr_date.getFullYear();
     let curr_month = curr_date.getMonth();
     
     const term_map= [
          "spring", // jan - april
          "spring",
          "spring",
          "spring",
          "summer", //jun - july
          "summer",
          "summer",
          "fall", //aug - dec
          "fall",
          "fall",
          "fall",
          "fall"
     ];
     
     const term_offsets = {
          "spring": 0,
          "summer": 1,
          "fall": 2 
          };
          
     const term_by_offset = [
          "spring","summer","fall"

     ];
     
     let curr_term = term_map[curr_month];
     let curr_term_offset = term_offsets[curr_term];
     
     for (let i=0;i<offset_in_terms;i++) {
     
          curr_term_offset--;
          if (curr_term_offset < 0) {
               curr_year--;
               curr_term_offset = 2;
          }
          curr_term = term_by_offset[curr_term_offset]
     }
     
     return { "year": curr_year.toString(), term: curr_term };

}



//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

// var firebaseDB = null;
// 
// function connectToFirebase() {
// 
//  var midtermDataURL = config.firebase_base_url + '/' + config.firebase_directory;
//      console.log("config.firebase_directory: " + config.firebase_directory);
//      console.log("config.firebase_base_url: " + config.firebase_base_url);
//      console.log("midtermDataURL: " + midtermDataURL);
// 
//      var firebaseDB = new Firebase(midtermDataURL);
// 
//      firebaseDB.authWithCustomToken(config.firebaseSecret, function(error, authData) {
//          if (error) {
//              console.error("Error: Login Failed: ", error);
//          }
//          else {
//              console.log("Login Succeeded!");
//              auth
//             
//          } // logged in successfully
//          
//      });
//      
//      return midtermData;
//      
// }

function monitorFirebase(year,term) {

     var midtermDataURL = config.firebase_base_url + '/' + config.firebase_directory + '/' + year + '/' + term + '/';
     console.log("config.firebase_directory: " + config.firebase_directory);
     console.log("config.firebase_base_url: " + config.firebase_base_url);
     console.log("midtermDataURL: " + midtermDataURL);


     var midtermData = new Firebase(midtermDataURL);

     midtermData.authWithCustomToken(config.firebaseSecret, function(error, authData) {
         if (error) {
             console.error("Error: Login Failed: ", error);
         }
         else {
             console.log("Login Succeeded for " + year + " " + term + "!", authData);
            
         } // logged in successfully
         
     });
     
      listenForChanges(midtermData);
}


//---------------------------------------------------------------------------------

function listenForChanges(midtermData) {
// listen for additons or changes to idp data

     
     console.log("listen for changes");
     
     midtermData.on('child_added', function(childSnapshot, prevChildKey) {
         // console.log(childSnapshot);
         console.notice("\n\nChild added at key: " + childSnapshot.key());
         processMidtermChild(midtermData,childSnapshot);
     });

     midtermData.on('child_changed', function(childSnapshot, prevChildKey) {
         // console.log(childSnapshot);
         console.notice("\n\nChild changed at key: " + childSnapshot.key());
         processMidtermChild(midtermData,childSnapshot);
     });
     
}

//---------------------------------------------------------------------------------

function setTimeStampForChildAtKey(firebaseDataRef,childSnapshot,subject_key,timestampKey) {

     // utility to save a timestamp into firebase, eg for confirmation email sent
     console.log("set timestamp for " + subject_key + " " + timestampKey);
     firebaseDataRef.child(childSnapshot.key()).child(subject_key).child(timestampKey).set(Date.now(), function(error) {});
}

//---------------------------------------------------------------------------------

function setCompletedForChild(firebaseDataRef,childSnapshot) {

     // utility to save a timestamp into firebase, eg for confirmation email sent
     console.log("completed for " + childSnapshot.child('student').child('fsuid') );
     firebaseDataRef.child(childSnapshot.key()).child('completed_timestamp').set(Date.now(), function(error) {});
}

//---------------------------------------------------------------------------------


/* logic:

if child has student signature, but has not been sent a confirmation email send confirmation to student.
once student confirmation has been sent, check if chair/cochair needs to sign and send them a reminder

if child has chair signature, but has not been sent a confirmation email, send confirmation to chair.
once chair confirmation has been sent, check if student needs to sign and send them a reminder


*/

//---------------------------------------------------------------------------------

function needs_confirmation(childSnapshot,subject_key) {

     console.log("need confirmation " + subject_key + ": " + childSnapshot.child(subject_key).child('signature_timestamp').val());
     console.log("confirmation sent " + subject_key + ": " + childSnapshot.child(subject_key).child('sent_conf_email_timestamp').val());

     var flag = (
               null != childSnapshot.child(subject_key).child('signature_timestamp').val() 
               && 
               null == childSnapshot.child(subject_key).child('sent_conf_email_timestamp').val()
          );
     console.log(flag  );
          
     return (
               null != childSnapshot.child(subject_key).child('signature_timestamp').val() 
               && null == childSnapshot.child(subject_key).child('sent_conf_email_timestamp').val()
          );

}

//---------------------------------------------------------------------------------


function needs_reminder(childSnapshot) {

     let keys = [ "chair", "student"];
     let needs = {
          "chair": { "signed": false, "reminder_sent": false},
          "student": { "signed": false, "reminder_sent": false},     
     }
     
     keys.forEach(function(k) {
          needs[k].signed =  childSnapshot.child(k).child('sent_conf_email_timestamp').val();
          needs[k].reminder_sent = childSnapshot.child(k).child('sent_reminder_email_timestamp').val();
     });
     
     if (needs['chair'].signed && !needs['student'].signed && !needs['student'].reminder_sent) {
          return 'student';
     }

     if (needs['student'].signed && !needs['chair'].signed && !needs['chair'].reminder_sent) {
          return 'chair';
     }

     return null;
     
}

//---------------------------------------------------------------------------------


function needs_completion_timestamp(childSnapshot) {

     console.log("need completion student "  + childSnapshot.child('student').child('signature_timestamp').val());
     console.log("need completion chair  "  + childSnapshot.child('chair').child('signature_timestamp').val());

     let flag = (
          null != childSnapshot.child('student').child('signature_timestamp').val()
          && 
          null != childSnapshot.child('chair').child('signature_timestamp').val()
           && 
          null == childSnapshot.child('completed_timestamp').val()
     );
     
     console.log("need completion flag  "  + flag);
     
     return (
          null != childSnapshot.child('student').child('signature_timestamp').val()
          && 
          null != childSnapshot.child('chair').child('signature_timestamp').val()
           && 
          null == childSnapshot.child('completed_timestamp').val()
     );

}

//---------------------------------------------------------------------------------

function processMidtermChild(midtermData,childSnapshot) {


    console.log("processMidtermChild: " + childSnapshot.key());

    if (needs_confirmation(childSnapshot,'student')) {
        // confirm with student, email chair and cochair to complete their section
        if (DEBUG) console.log('student_signature_timestamp');
        student_signed(midtermData,childSnapshot);
    }

    if (needs_confirmation(childSnapshot,'chair')) {
        // confirm with chair and student
        if (DEBUG) console.log('chair_signature_timestamp');
        chair_signed(midtermData,childSnapshot, 0);
    }
    if (needs_confirmation(childSnapshot,'cochair')) {
        // confirm with cochair and  student
        if (DEBUG) console.log('cochair_signature_timestamp');
        chair_signed(midtermData,childSnapshot, 1);
    }
    
    let key = needs_reminder(childSnapshot);
    if (key) {
          if (DEBUG) console.log(key + ' needs reminder');
          if ('student' == key) {
               sendStudentReminderEmail(midtermData ,childSnapshot);
          }
          if ('chair' == key) {
               sendChairReminderEmail(midtermData ,childSnapshot);
          }
    }
    
    
    if (needs_completion_timestamp(childSnapshot)) {
        // confirm with student, email chair and cochair to complete their section
        if (DEBUG) console.log('needs completion');
        setCompletedForChild(midtermData,childSnapshot);
    }

}

//---------------------------------------------------------------------------------------

function sendChairReminderEmail(midtermData,childSnapshot) {

     
    var first_name = childSnapshot.child('student').child('first_name').val().toString();
    var last_name = childSnapshot.child('student').child('last_name').val().toString();
    var fsuid = childSnapshot.child('student').child('fsuid').val().toString();
    var term = childSnapshot.child('term').val().toString();
    var year = childSnapshot.child('year').val().toString();



    var chair_first_name = childSnapshot.child("chair").child('first_name').val().toString();
    var chair_last_name = childSnapshot.child("chair").child('last_name').val().toString();
    var chair_email = childSnapshot.child("chair").child('email').val().toString();
    var chair_fsuid = chair_last_name
    if (null != childSnapshot.child("chair").child('fsuid').val())
    var chair_fsuid = childSnapshot.child("chair").child('fsuid').val().toString();


    console.notice("chair" + ' Reminder: ' + last_name + ' ' + fsuid);

    // var chair_email_message = 'Dear Dr. ' + chair_name + ':\n\n Thank you for submitting the Annual Review form for ' + term + ' ' + year + ' for ' + first_name + ' ' + last_name + '.\n\nThe other members of the student\'s committee will be asked by email to acknowledge the review.\n\nIf you have any questions, feel free to contact ' + config.grad_coordinator + '. \n\n';

    var letter_fields = {
        "term": term,
        "year": year,
        "first_name": first_name,
        "last_name": last_name,
        "chair_first_name": chair_first_name,
        "chair_last_name": chair_last_name,
        "form_url": (config.gradawan_base_url + '/idp/?id=' + fsuid + '&year=' + year + '&term=' + term),
        "grad_coordinator": config.grad_coordinator,
        "grad_coordinator_contact": config.grad_coordinator_contact,
        "gradphile_name": config.gradphile_name


    };

    var email_message = mustache.render(templates['chair_reminder_email_template'], letter_fields);

    var chair_email_subject = term + ' ' + year + ' IDP to be signed';

    if (DEBUG) {
        chair_email = "tom+chair@houptlab.org";
    }

    // send email with reminder
    transactq.send_email_with_reminder(fsuid, chair_fsuid, year, term, chair_email, chair_email_subject, email_message);
    
     
     setTimeStampForChildAtKey(midtermData,childSnapshot,'chair','sent_reminder_email_timestamp');
     
     

     
}

//---------------------------------------------------------------------------------------

function sendStudentReminderEmail(midtermData,childSnapshot) {

     
      var first_name = childSnapshot.child('student').child('first_name').val().toString();
    var last_name = childSnapshot.child('student').child('last_name').val().toString();
    var fsuid = childSnapshot.child('student').child('fsuid').val().toString();
    var student_email = childSnapshot.child('student').child('email').val().toString();
    var term = childSnapshot.child('term').val().toString();
    var year = childSnapshot.child('year').val().toString();

    var chair_first_name = childSnapshot.child('chair').child('first_name').val().toString();
    var chair_last_name = childSnapshot.child('chair').child('last_name').val().toString();


    console.notice('Student Reminder: ' + last_name + ' ' + fsuid);

    var letter_fields = {
        "term": term,
        "year": year,
        "first_name": first_name,
        "last_name": last_name,
        "chair_first_name": chair_first_name,
        "chair_last_name": chair_last_name,
        "form_url": (config.gradawan_base_url + '/idp/?id=' + fsuid + '&year=' + year + '&term=' + term),
        "grad_coordinator": config.grad_coordinator,
        "grad_coordinator_contact": config.grad_coordinator_contact,
        "gradphile_name": config.gradphile_name

    };

    var student_email_message = mustache.render(templates['student_reminder_email_template'], letter_fields);
    var student_email_subject = term + ' ' + year + ' IDP to be signed';

    if (DEBUG) {
        student_email = "tom+student@houptlab.org";
    }

    // send email without reminder
    transactq.send_email(fsuid, fsuid, year, term, student_email, student_email_subject, student_email_message);

     setTimeStampForChildAtKey(midtermData,childSnapshot,'student','sent_reminder_email_timestamp');

}


//---------------------------------------------------------------------------------------

function student_signed(midtermData,childSnapshot) {

    var first_name = childSnapshot.child('student').child('first_name').val().toString();
    var last_name = childSnapshot.child('student').child('last_name').val().toString();
    var fsuid = childSnapshot.child('student').child('fsuid').val().toString();
    var student_email = childSnapshot.child('student').child('email').val().toString();
    var term = childSnapshot.child('term').val().toString();
    var year = childSnapshot.child('year').val().toString();

    var chair_first_name = childSnapshot.child('chair').child('first_name').val().toString();
    var chair_last_name = childSnapshot.child('chair').child('last_name').val().toString();


    console.notice('Student Signed: ' + last_name + ' ' + fsuid);

    var letter_fields = {
        "term": term,
        "year": year,
        "first_name": first_name,
        "last_name": last_name,
        "chair_first_name": chair_first_name,
        "chair_last_name": chair_last_name,
        "form_url": (config.gradawan_base_url + '/idp/?id=' + fsuid + '&year=' + year + '&term=' + term),
        "grad_coordinator": config.grad_coordinator,
        "grad_coordinator_contact": config.grad_coordinator_contact,
        "gradphile_name": config.gradphile_name

    };

    var student_email_message = mustache.render(templates['student_confirmation_email_template'], letter_fields);
    var student_email_subject = term + ' ' + year + ' IDP acknowledgement';

    if (DEBUG) {
        student_email = "tom+student@houptlab.org";
    }

    // send email without reminder
    transactq.send_email(fsuid, fsuid, year, term, student_email, student_email_subject, student_email_message);

     setTimeStampForChildAtKey(midtermData,childSnapshot,'student','sent_conf_email_timestamp');

//      if (needs_reminder(childSnapshot,'chair')) {
//           sendChairReminderEmail(midtermData,childSnapshot);
//      }


}


//---------------------------------------------------------------------------------------

function chair_signed(midtermData,childSnapshot, chair_index) {

    // chair_index is 0 for chair, 1 for cochair1, 2 for cochair2

    var first_name = childSnapshot.child('student').child('first_name').val().toString();
    var last_name = childSnapshot.child('student').child('last_name').val().toString();
    var fsuid = childSnapshot.child('student').child('fsuid').val().toString();
    var term = childSnapshot.child('term').val().toString();
    var year = childSnapshot.child('year').val().toString();


    var chair_key = "cochair" + chair_index;

    if (chair_index == '0') {
        chair_key = 'chair';
    }

    var chair_conf_key = 'sent_conf_email_timestamp';

    var chair_first_name = childSnapshot.child(chair_key).child('first_name').val().toString();
    var chair_last_name = childSnapshot.child(chair_key).child('last_name').val().toString();
    var chair_email = childSnapshot.child(chair_key).child('email').val().toString();
    var chair_fsuid = chair_last_name;
    if ( childSnapshot.child(chair_key).hasChild('fsuid') ) {
    	 chair_fsuid = childSnapshot.child(chair_key).child('fsuid').val().toString();
    }


    console.notice(chair_key + ' Signed: ' + last_name + ' ' + fsuid);

    // var chair_email_message = 'Dear Dr. ' + chair_name + ':\n\n Thank you for submitting the Annual Review form for ' + term + ' ' + year + ' for ' + first_name + ' ' + last_name + '.\n\nThe other members of the student\'s committee will be asked by email to acknowledge the review.\n\nIf you have any questions, feel free to contact ' + config.grad_coordinator + '. \n\n';

    var letter_fields = {
        "term": term,
        "year": year,
        "first_name": first_name,
        "last_name": last_name,
        "chair_first_name": chair_first_name,
        "chair_last_name": chair_last_name,
        "form_url": (config.gradawan_base_url + '/idp/?id=' + fsuid + '&year=' + year + '&term=' + term),
        "grad_coordinator": config.grad_coordinator,
        "grad_coordinator_contact": config.grad_coordinator_contact,
        "gradphile_name": config.gradphile_name


    };

    var email_message = mustache.render(templates['chair_confirmation_email_template'], letter_fields);

    var chair_email_subject = term + ' ' + year + ' IDP acknowledgement';

    if (DEBUG) {
        chair_email = "tom+chair@houptlab.org";
    }

    // send email without reminder
    transactq.send_email(fsuid, chair_fsuid, year, term, chair_email, chair_email_subject, email_message);

    setTimeStampForChildAtKey(midtermData,childSnapshot,'chair',chair_conf_key);

//      if (needs_reminder(childSnapshot,'student')) {
//           sendStudentReminderEmail(midtermData,childSnapshot)
//      }


} // chair signed

//---------------------------------------------------------------------------------------



     monitorFirebase("2019","fall");
     monitorFirebase("2020","spring");
     
     monitorFirebase("2020","summer");
     monitorFirebase("2020","fall");
     
     /*
     monitorFirebase("2021","spring");
     monitorFirebase("2021","summer");
     monitorFirebase("2021","fall");
*/