/*
bc_utilities.js
commonly used routines:
function backupFile(filename);
make a copy of file with YYYYmmdd_HHMMSS.BAK
function writeUpdateFile(file_key,key);
write current time to file with name "last_<file_key>_updated.json" and to subobject given by key
key is typically the name of the script that made the last update
will preserve any pre-existing keys (so we have history of when each key was last updated)
{ "last_updated": <time_now>,
"<key>": {
"last_updated": <time_now>
}
}
function initializeFromCSVPathWithKey(path,key);
if key is null, then load as array of rows
function initializeFromYAMLPath(path);
function deepCopy(originalObject) return a deep copy of the original object
function readJSONfromCWD(filePath)
returns json from the given path, assuming path is within curren working directory
function readJSONfromAppDir(dirname,filePath)
returns json from the given path, assuming path is__dirname (same dir a calling node script)
isUndefined(id)
isNull(id)
isUndefinedOrIsNull(id)
notUndefined(id)
notNull(id)
notUndefinedAndNotNull(id)
*/
const fs = require('fs');
const path = require('path');
const execFileSync = require('child_process').execFileSync;
const parse = require('csv-parse/lib/sync');
// read in srad.csv for year
const yaml = require('js-yaml');
/*-------------------------------------------------------------------------*/
function getDatetimeString(date_object) {
let month = (date_object.getMonth() + 1).toString().padStart(2, '0');
let date = date_object.getDate().toString().padStart(2, '0');
let hour = date_object.getHours().toString().padStart(2, '0');
let minute = date_object.getMinutes().toString().padStart(2, '0');
let seconds = date_object.getSeconds().toString().padStart(2, '0');
let datetime_string = "" + date_object.getFullYear() + month + date + "_" + hour + minute + seconds;
return datetime_string;
}
function backupFile(filename) {
// make a copy of file with YYYYmmddhhMMSS.BAK appended to end of file name
// and put copy into _backups directory in the files parent directory
// eg backupFile("/dir1/dir2/myfile.json")
// -> "/dir/dir2/_backups/myfile.json.202001311653.BAK"
// backup file date based on last modification date of the file,
// and NOT the current time that backup is called
if (!fs.existsSync(filename)) {
return;
}
let stats = fs.statSync(filename);
let modification_time = stats.mtime;
let time_string = getDatetimeString(modification_time);
let backup_path = path.dirname(filename) + "/_backups";
if (!fs.existsSync(backup_path)) {
fs.mkdirSync(backup_path);
}
let backup_filename = backup_path + "/" + path.basename(filename) + "." + time_string + ".BAK";
fs.copyFileSync(filename, backup_filename);
}
/*-------------------------------------------------------------------------*/
function writeUpdateFile(file_key, key) {
/*
write current time to jekyll/_data/file with name "last_<file_key>_updated.json" and to subobject given by key
key is typically the name of the script that made the last update
will preserve any pre-existing keys (so we have history of when each key was last updated)
{ "last_updated": <time_now>,
"<key>": {
"last_updated": <time_now>
}
}
*/
const file_name = "last_" + file_key + "_update.json";
var update = {};
if (fs.existsSync(file_name)) {
update = JSON.parse(fs.readFileSync(file_name));
}
if (null != key) {
if (typeof update[key] == "undefined") {
update[key] = {};
}
update[key]['last_updated'] = new Date().toLocaleString();
}
update['last_updated'] = new Date().toLocaleString();
fs.writeFileSync(__dirname + "/jekyll/_data/" + file_name, JSON.stringify(update, null, 5));
}
/*-------------------------------------------------------------------------*/
function initializeFromCSVPathWithKey(path, key) {
// if key null, then load as rows
if (!fs.existsSync(path)) {
console.log("No CSV file at: " + path + "!!");
process.exit(1);
}
let csv_string = fs.readFileSync(path);
let csv = null;
if (null == key) {
csv = parse(csv_string, {
'columns': true
});
}
else {
csv = parse(csv_string, {
'columns': true,
'objname': key
});
}
return csv;
}
/*-------------------------------------------------------------------------*/
function initializeFromYAMLPath(path) {
if (!fs.existsSync(path)) {
console.log("No YAML file at: " + path + "!!");
process.exit(1);
}
return (yaml.safeLoad(fs.readFileSync(path, 'utf8')));
}
/*-------------------------------------------------------------------------*/
function deepCopy(originalObject) {
let strValue = JSON.stringify(originalObject);
return JSON.parse(strValue);
}
/*-------------------------------------------------------------------------*/
function readJSON(filePath) {
let data = fs.readFileSync(filePath);
return JSON.parse(data);
}
function readJSONfromCWD(filePath) {
// path.resolve(yourPath) === path.normalize(yourPath).replace( RegExp(path.sep+'$'), '' );
let data = fs.readFileSync(path.resolve(filePath));
return JSON.parse(data);
}
function readJSONfromAppDir(dirname, filePath) {
// have to pass in __dirname from calling app
let data = fs.readFileSync(path.join(dirname, filePath));
return JSON.parse(data);
}
/*-------------------------------------------------------------------------*/
function isUndefined(id) {
return ("undefined" == typeof id);
}
function isNull(id) {
return (null == id);
}
function isUndefinedOrIsNull(id) {
if (isUndefined(id)) return true;
if (isNull(id)) return true;
return false;
}
/*-------------------------------------------------------------------------*/
function notUndefined(id) {
return ("undefined" != typeof id);
}
function notNull(id) {
return (null != id);
}
function notUndefinedAndNotNull(id) {
return (notUndefined(id) && notNull(id));
}
/*-------------------------------------------------------------------------*/
/**
returns true if parent, or parent[child], is undefined or null
*/
function isUndefinedOrIsNullParentAndChild(parent, child) {
if (isUndefined(parent)) return true;
if (isNull(parent)) return true;
if (isUndefined(parent[child])) return true;
if (isNull(parent[child])) return true;
return false;
}
function notUndefinedAndNotNullParentAndChild(parent, child) {
if (notUndefined(parent) && notNull(parent)) {
return (notUndefined(parent[child]) && notNull(parent[child]));
}
return false;
}
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
function isEmptyObject(theObject) {
// returns true if:
// - theObject is null or undefined
// - theObject is a string of zero length, or contains only white space
// - theObject is an array of zero length
// - theObject has no keys
// - theObject has keys, but key-value isEmptyObject
// console.log("\n\n\n" + theObject);
if (isUndefinedOrIsNull(theObject)) {
// console.log("null or undefined");
return true;
}
if (typeof theObject == "string") {
return ((theObject.length == 0) || !(/\S/.test(theObject)));
}
if (typeof theObject == "object") {
if (Array.isArray(theObject)) {
return (theObject.length == 0);
}
if (Object.keys(theObject).length == 0) {
// console.log("empty object");
return true;
}
let empty_flag = true;
Object.keys(theObject).forEach(function(key) {
// console.log("Subkey: " + key);
// if any of the subkeys are NOT empty, then object isn't empty
if (!isEmptyObject(theObject[key])) {
// console.log("Not Empty Subkey");
empty_flag = false;
}
});
// object must be empty
if (empty_flag) {
// console.log("object with empty keys");
}
return empty_flag;
}
// otherwise it is a number or Boolean or symbol or bigint or function
// console.log("Not Empty");
return false;
} // isEmptyObject
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
function removeInvalidKeysFromObject(theObject) {
// call this routine on each student in $scope.students before sending to eve/mongodb
// to strip out all keys with null or empty values from the data structure
// removeInvalids recursively removes undefined/nulls/empty/whitespace from object, subobjects, and subarrays
// if object ends up "empty" (ie object has keys, but key-values are empty), then it deletes that object too
//// Compact arrays with null entries; delete keys from objects with null value
// https://stackoverflow.com/questions/18515254/recursively-remove-null-values-from-javascript-object
function removeInvalids(obj) {
let isArray = obj instanceof Array;
// if (isArray) {
// console.log(obj);
// console.log("array length: " + obj.length);
// console.log("keys length: " + Object.keys(obj).length);
// console.log("values length: " + Object.values(obj).length);
// console.log("\n\n");
// }
// iterate backwards through keys so we catch all members of array even after splicing
for (let i = (Object.keys(obj).length - 1); i >= 0; i--) {
let k = Object.keys(obj)[i];
if (!k.includes("$")) {
if (isEmptyObject(obj[k])) {
// if (obj[k] === undefined ||
// obj[k] === null ||
// obj[k] === '' ||
// !(/\S/.test(obj[k]))
// ) {
isArray ? obj.splice(i, 1) : delete obj[k];
}
else if (typeof obj[k] == "object") {
removeInvalids(obj[k]);
if (isEmptyObject(obj[k])) {
delete obj[k];
}
}
} // key doesn't include "$"
} // next key
} // removeNulls
removeInvalids(theObject);
return theObject;
} // removeInvalidKeysFromObject
function removeInvalidKeysFromObjectDebug(theObject) {
// call this routine on each student in $scope.students before sending to eve/mongodb
// to strip out all keys with null or empty values from the data structure
// removeInvalids recursively removes undefined/nulls/empty/whitespace from object, subobjects, and subarrays
// if object ends up "empty" (ie object has keys, but key-values are empty), then it deletes that object too
//// Compact arrays with null entries; delete keys from objects with null value
// https://stackoverflow.com/questions/18515254/recursively-remove-null-values-from-javascript-object
var recurse_level = 0;
function removeInvalids(obj) {
recurse_level++;
let spacer = "";
for (var j = 0; j < recurse_level; j++) spacer += " ";
var isArray = obj instanceof Array;
// iterate backwards through keys so we catch all members of array even after splicing
for (var i = (Object.keys(obj).length - 1); i >= 0; i--) {
var k = Object.keys(obj)[i];
console.log(spacer + recurse_level + " key " + i + " " + k);
if (k == "academic_plans") {
console.log("GOT TO ACADEMIC PLANS");
}
if (obj[k] === undefined ||
obj[k] === null ||
obj[k] === '' ||
!(/\S/.test(obj[k]))
) {
isArray ? obj.splice(i, 1) : delete obj[k];
if (k == "discontinued" && obj.plan_code == "BIOLOGYPD" &&
obj["defense_date"] == "11/8/2019") {
console.log("discontinued - > " + obj[k] + " still has key " + Object.keys(obj).includes(k));
}
}
else if (typeof obj[k] == "object") {
if (k == "academic_plans") {
let academic_plans_flag = true;
console.log("RECURSING ON ACADEMIC PLANS " + Object.keys(obj[k]).length);
}
removeInvalids(obj[k]);
if (isEmptyObject(obj[k])) {
delete obj[k];
}
}
}
recurse_level--;
} // removeNulls
// let theObjectCopy = JSON.parse(JSON.stringify(theObject),null," ");
removeInvalids(theObject);
return theObject;
} // removeInvalidKeysFromObject
// ------------------------------------------------------------------------
var _removeInvalidKeysFromStudent = function(student) {
// call this routine on each student in $scope.students before sending to eve/mongodb
// to strip out all keys with null or empty values from the data structure
// removeInvalids recursively removes undefined/nulls/empty/whitespace from object, subobjects, and subarrays
//// Compact arrays with null entries; delete keys from objects with null value
// https://stackoverflow.com/questions/18515254/recursively-remove-null-values-from-javascript-object
function removeInvalids(obj) {
var isArray = obj instanceof Array;
// if (isArray) {
// console.log(obj);
// console.log("array length: " + obj.length);
// console.log("keys length: " + Object.keys(obj).length);
// console.log("values length: " + Object.values(obj).length);
// console.log("\n\n");
// }
// iterate backwards through keys so we catch all members of array even after splicing
for (var i = Object.keys(obj).length - 1; i >= 0; i--) {
var k = Object.keys(obj)[i];
if (!k.includes("$")) {
// if (isArray && i == 1) { console.log(k + ": " + obj[k]); }
if ((obj[k] instanceof Array) && (0 == obj[k].length)) {
isArray ? obj.splice(i, 1) : delete obj[k];
}
else if ((obj[k] instanceof Object) && (0 == Object.keys(obj[k]).length)) {
isArray ? obj.splice(i, 1) : delete obj[k];
}
else if (typeof obj[k] == "string" && obj[k].length == 0) {
isArray ? obj.splice(i, 1) : delete obj[k];
}
else if (obj[k] === undefined ||
obj[k] === null ||
obj[k] === "" // is === "" equivalent to === '' ? because "" fields seem to be getting through...
||
!(/\S/.test(obj[k]))
) {
isArray ? obj.splice(i, 1) : delete obj[k];
}
else if (typeof obj[k] == "object") {
removeInvalids(obj[k]);
// object may now be empty, in which case delete it
if (0 == Object.keys(obj[k]).length) {
isArray ? obj.splice(i, 1) : delete obj[k];
}
}
} // key doesn't contain "$"
} // next key
} // removeInvalids
removeInvalids(student);
return student;
};
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// TEST OF REMOVE INVALID OBJECTS
//const undefinedObject;
const nullObject = null;
const trueObject = true;
const falseObject = false;
const emptyObject = {};
const emptyArray = [];
const emptyString = "";
const spaceString = " ";
const spaceTabReturnString = " \t \n ";
const objectWithEmptyObjects = {
"ok": {
"name": "Tom",
"foo": "bar"
},
"no_missing": {
"name": "Tom",
"foo": "bar",
"missingString": emptyString,
"missingArray": emptyArray,
"missingObject": emptyObject
},
"ok_array": ["element1", "element2", "element3"],
"no_missing_array": ["element1", nullObject, emptyString, spaceString, "element2"],
"array1": nullObject,
"array2": emptyArray,
"array3": [nullObject, emptyString, spaceString, emptyObject],
"array4": [trueObject, falseObject],
"array5": ["foo", emptyObject],
"objnull": nullObject,
"obj0": emptyObject,
"obj1": {
"obj2": {
"foo": "bar",
"obj3": {
"nullObject": nullObject,
"emptyString": emptyString,
"emptyArray": emptyArray,
"foo": "bar"
},
"obj4": {
"nullObject": nullObject,
"emptyString": emptyString,
"emptyArray": emptyArray,
}
}
}
};
const onlyValidObjects = {
"ok": {
"name": "Tom",
"foo": "bar"
},
"no_missing": {
"name": "Tom",
"foo": "bar"
},
"ok_array": ["element1", "element2", "element3"],
"no_missing_array": ["element1", "element2"],
"array4": [true, false],
"array5": ["foo"],
"obj1": {
"obj2": {
"foo": "bar",
"obj3": {
"foo": "bar"
}
}
}
};
// console.log(["foo",{}].length);
const onlyValidObjects_string = JSON.stringify(onlyValidObjects, null, " ");
const emptyObjects_string = JSON.stringify(objectWithEmptyObjects, null, " ");
const strippedObject = removeInvalidKeysFromObject(objectWithEmptyObjects);
const strippedStudent = _removeInvalidKeysFromStudent(objectWithEmptyObjects);
const strippedObject_string = JSON.stringify(strippedObject, null, " ");
const strippedStudent_string = JSON.stringify(strippedStudent, null, " ");
if (onlyValidObjects_string != strippedObject_string) {
console.log("FAILED removeInvalidKeysFromObject");
console.log(emptyObjects_string);
console.log(strippedObject_string);
process.exit(1);
}
if (onlyValidObjects_string != strippedStudent_string) {
console.log("FAILED _removeInvalidKeysFromStudent");
process.exit(1);
}
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
var fsuid_regex = /employeeID: (.+)\n/;
var email_regex = /mail: (.+)\n/;
var dept_regex = /department: ([^\()]+)/;
var photo_regex = /url: (.+)\n/;
var given_regex = /givenName: (.+)\n/;
var CN_regex = /dn: CN=([a-z0-9]+)\,/;
let ldap_cache = {};
// check how old the ldap cache is:
// if > 1 week, then delete it. (new one will be created with first look up)
// otherwise read it in...
if (fs.existsSync(__dirname + "/_ldap_cache.json")) {
if (fs.existsSync(__dirname + "/_ldap_cache_started.json")) {
let ldap_cache_started = readJSON(__dirname + "/_ldap_cache_started.json");
let time_now = Date.now();
if (time_now - ldap_cache_started.timestamp < (7* 86400000)) {
ldap_cache = readJSON(__dirname + "/_ldap_cache.json");
}
else {
fs.unlinkSync(__dirname + "/_ldap_cache.json");
}
}
}
function getLDAPInfo(username, password, emplid) {
/*
given emplid, looks up fsuid via ldap
return either fsuid or null
example ldap lookup by emplid
```
ldapsearch -L -L -L -h fsu-dc-1.fsu.edu -D <fsuid@fsu.edu> -w <password> -b 'dc=fsu,dc=edu' -s sub 'fsuEduEMPLID=200625657' employeeID
```
returns:
```
dn: CN=mps18bg,OU=PEOPLE,DC=fsu,DC=edu
employeeID: mps18bg
# refldap://mscloud.fsu.edu/DC=mscloud,DC=fsu,DC=edu
# refldap://fsu.edu/CN=Configuration,DC=fsu,DC=edu
# refldap://ForestDnsZones.fsu.edu/DC=ForestDnsZones,DC=fsu,DC=edu
# refldap://DomainDnsZones.fsu.edu/DC=DomainDnsZones,DC=fsu,DC=edu
```
```
ldapsearch -L -L -L -h fsu-dc-1.fsu.edu -D thoupt@fsu.edu -w <password> -b 'dc=fsu,dc=edu' -s sub 'fsuEduEMPLID=000110293' employeeID mail department
```
returns
```
dn: CN=ebangi,OU=PEOPLE,DC=fsu,DC=edu
department: Biological Science (BIOLOGY) (074000)
employeeID: ebangi
mail: ebangi@fsu.edu
# refldap://mscloud.fsu.edu/DC=mscloud,DC=fsu,DC=edu
# refldap://fsu.edu/CN=Configuration,DC=fsu,DC=edu
# refldap://ForestDnsZones.fsu.edu/DC=ForestDnsZones,DC=fsu,DC=edu
# refldap://DomainDnsZones.fsu.edu/DC=DomainDnsZones,DC=fsu,DC=edu
```
=========
ldapsearch -L -L -L -h fsu-dc-1.fsu.edu -D thoupt@fsu.edu -w <password> -b 'dc=fsu,dc=edu' -s sub 'fsuEduEMPLID=200625657'
dn: CN=mps18bg,OU=PEOPLE,DC=fsu,DC=edu
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: mps18bg
sn: Schumm
title: Graduate Assistant in Teaching
description: Mr Matthew Philip Schumm
physicalDeliveryOfficeName: 2065 KIN MC 4295
givenName: Matthew
distinguishedName: CN=mps18bg,OU=PEOPLE,DC=fsu,DC=edu
instanceType: 4
whenCreated: 20181222134358.0Z
whenChanged: 20200117210152.0Z
displayName: Matthew Schumm
uSNCreated: 5715116
memberOf: CN=ug-FSU-Students-All,OU=Special Purpose Groups,OU=FSU Special Purp
ose,DC=fsu,DC=edu
memberOf: CN=ug-FSU-Employees-All,OU=Special Purpose Groups,OU=FSU Special Pur
pose,DC=fsu,DC=edu
uSNChanged: 937369625
department: Biological Science (BIOLOGY) 074000
company: FSUID = MPS18BG
proxyAddresses: x500:/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOH
F23SPDLT)/cn=Recipients/cn=db18e29ac3bf49079470b9367270d591-mps18bg
proxyAddresses: SMTP:mschumm@fsu.edu
proxyAddresses: smtp:mps18bg@fsu.edu
proxyAddresses: X400:C=US;A= ;P=Florida State Un;O=OLYMPUS;S=Schumm;G=Matthew;
proxyAddresses: smtp:mps18bg@fsu.mail.onmicrosoft.com
targetAddress: SMTP:mps18bg@fsu.mail.onmicrosoft.com
extensionAttribute6: EMPLOYEE
mailNickname: mps18bg
extensionAttribute15: EMPLOYEE,FACULTY,GRAD,OPS,STUDENT
employeeType: Active
name: mps18bg
objectGUID:: MuiR+9frw0SyHX2PZXafBw==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
employeeID: mps18bg
badPasswordTime: 0
lastLogoff: 0
lastLogon: 132108785589384411
pwdLastSet: 132172645540782866
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAxrtQevGzEnEH5TsrEj8KAA==
accountExpires: 0
logonCount: 1
sAMAccountName: mps18bg
sAMAccountType: 805306368
showInAddressBook: CN=Default Global Address List,CN=All Global Address Lists,
CN=Address Lists Container,CN=Florida State University,CN=Microsoft Exchange,
CN=Services,CN=Configuration,DC=fsu,DC=edu
legacyExchangeDN: /o=Florida State University/ou=Exchange Administrative Group
(FYDIBOHF23SPDLT)/cn=Recipients/cn=00bbfe6de33948c7943f08acc93a75a2
userPrincipalName: mps18bg@fsu.edu
url: http://images.its.fsu.edu/fsucardimages/small/01PWHPQG.JPG
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=fsu,DC=edu
dSCorePropagationData: 20190814195154.0Z
dSCorePropagationData: 20190814192313.0Z
dSCorePropagationData: 20190718213640.0Z
dSCorePropagationData: 20190709173138.0Z
dSCorePropagationData: 16010714223649.0Z
lastLogonTimestamp: 132180643450412373
textEncodedORAddress: X400:C=US;A= ;P=Florida State Un;O=OLYMPUS;S=Schumm;G=Ma
tthew;
mail: mschumm@fsu.edu
manager: CN=dokamoto,OU=PEOPLE,DC=fsu,DC=edu
middleName: Philip
msExchPoliciesExcluded: {26491cfc-9e50-4857-861b-0cb8df22b5d7}
msExchVersion: 88218628259840
fsuEduAffiliation: EMPLOYEE,FACULTY,GRAD,OPS,STUDENT
fsuEduAffiliations: STUDENT
fsuEduAffiliations: FACULTY
fsuEduAffiliations: EMPLOYEE
fsuEduAffiliations: OPS
fsuEduAffiliations: GRAD
msExchUMDtmfMap: emailAddress:6724866
msExchUMDtmfMap: lastNameFirstName:7248666288439
msExchUMDtmfMap: firstNameLastName:6288439724866
msExchRecipientDisplayType: -2147483642
msExchRecipientTypeDetails: 2147483648
msExchUserHoldPolicies: 98E9BABD09A04bcf8455A58C2AA74182
fsuEduEMPLID: 200625657
fsuEduAppRoles: CS_ADMN_STDT_CNT
msExchRemoteRecipientType: 1
# refldap://mscloud.fsu.edu/DC=mscloud,DC=fsu,DC=edu
# refldap://fsu.edu/CN=Configuration,DC=fsu,DC=edu
# refldap://ForestDnsZones.fsu.edu/DC=ForestDnsZones,DC=fsu,DC=edu
# refldap://DomainDnsZones.fsu.edu/DC=DomainDnsZones,DC=fsu,DC=edu
=========
ldapsearch -L -L -L -h fsu-dc-1.fsu.edu -D thoupt@fsu.edu -w <password> -b 'dc=fsu,dc=edu' -s sub 'fsuEduEMPLID=000024253'
dn: CN=thoupt,OU=PEOPLE,DC=fsu,DC=edu
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: thoupt
sn: Houpt
title: Professor 9 Mo SAL
description: Thomas A Houpt
physicalDeliveryOfficeName: 3010 MSB:1 MC 4300:1
telephoneNumber: 850/644-4424
facsimileTelephoneNumber: --
givenName: Thomas
distinguishedName: CN=thoupt,OU=PEOPLE,DC=fsu,DC=edu
instanceType: 4
whenCreated: 20110316215523.0Z
whenChanged: 20200331005852.0Z
displayName: Thomas Houpt
uSNCreated: 134843
memberOf: CN=ug-FSU-Employees-All,OU=Special Purpose Groups,OU=FSU Special Pur
pose,DC=fsu,DC=edu
memberOf: CN=dl-neuro-ctp,OU=Neuro,OU=FSU-Dept-Groups,DC=fsu,DC=edu
memberOf: CN=dl-sfn-neuro,OU=Neuro,OU=FSU-Dept-Groups,DC=fsu,DC=edu
memberOf: CN=dl-everyone-neuro,OU=Neuro,OU=FSU-Dept-Groups,DC=fsu,DC=edu
memberOf: CN=dl-neuro-gfs,OU=Neuro,OU=FSU-Dept-Groups,DC=fsu,DC=edu
memberOf: CN=dl-neuro-faculty,OU=Neuro,OU=FSU-Dept-Groups,DC=fsu,DC=edu
memberOf: CN=ug-TEC-CurrentInstructors,OU=Technology Enhanced Classrooms,OU=Co
mputing Technology Support Managed,OU=FSU-Dept-Groups,DC=fsu,DC=edu
uSNChanged: 1513368190
department: Biological Science (BIOLOGY) (074000)
company: FSUID = thoupt
deliverAndRedirect: TRUE
proxyAddresses: SMTP:houpt@neuro.fsu.edu
proxyAddresses: smtp:thoupt@fsu.edu
proxyAddresses: x500:/o=Florida State University/ou=Exchange Administrative Gr
oup (FYDIBOHF23SPDLT)/cn=Recipients/cn=thoupt4fc
proxyAddresses: smtp:thoupt@fsu.mail.onmicrosoft.com
proxyAddresses: SIP:thoupt@fsu.edu
proxyAddresses: X500:/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOH
F23SPDLT)/cn=Recipients/cn=5b056572065147838b6c5ab0b85f2d09-thoupt
proxyAddresses: smtp:thoupt@admin.fsu.edu
proxyAddresses: smtp:houpt@fsu.edu
proxyAddresses: smtp:thoupt@mailer.fsu.edu
proxyAddresses: smtp:thomas.houpt@fsu.edu
proxyAddresses: smtp:thomas.a.houpt@fsu.edu
proxyAddresses: X400:C=US;A= ;P=Florida State Un;O=OLYMPUS;S=Houpt;G=Thomas;
targetAddress: SMTP:thoupt@fsu.mail.onmicrosoft.com
extensionAttribute6: EMPLOYEE
directReports: CN=smstanley,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=sbebus,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jsun4,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=mcortez,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=sgong2,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=cchang2,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jac18gf,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dstorace,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=knl13,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=rvincis,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=ebangi,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=wwb15,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dokamoto,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=xwang18,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=sks14b,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=pfraser,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jmc14r,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=arassweiler,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=rcc08e,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=rlh15b,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=qyin,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=smiller,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dm16g,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=ytian3,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jfeng3,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=kgarner2,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=smccoy,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=clg11g,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dhoule,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=sburgess,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=smarks,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=sr13r,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=aj09f,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=mcharreldennis,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=elemmon,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=amw08e,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=ssteppan,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jtravis,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=acw05d,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=eduval,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=gerickson,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=ptrombley,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jwulff,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=tmiller,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=llyons,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=kahughes,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=amast,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=kchodyla,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dfadool,OU=Graduate School,OU=Computing Technology Support M
anaged,OU=FSU-Dept-Accounts,DC=fsu,DC=edu
directReports: CN=athistle,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=fzhu,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=kmjones2,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=hbass,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=bchadwick,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=hyu,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=mstroupe,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=drokyta,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=ktaylor,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jhdennis,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=ysu,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=jfadool,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=kmcginnis,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=nunderwood,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=kdixon,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=awinn,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=beh10d,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=hcui2,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=bjg04c,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=htang,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dgilbert,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=astuy,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=dlevitan,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=bwashburn,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=pfajer,OU=Institute of Molecular Biophysics,OU=FSU-Dept-Acco
unts,DC=fsu,DC=edu
directReports: CN=yhuang,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=vcarter,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=binouye,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=egranger,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=pchase,OU=PEOPLE,DC=fsu,DC=edu
directReports: CN=slenhert,OU=PEOPLE,DC=fsu,DC=edu
mailNickname: thoupt
extensionAttribute11:: QmlvbG9naWNhbCBTY2llbmNlIChCSU9MT0dZKSA=
extensionAttribute12: 74000
extensionAttribute13: BIOLOGICAL SCIENCE
extensionAttribute15: 9_10MONTH,EMPLOYEE,FACULTY
employeeType: Active
name: thoupt
objectGUID:: 0wEUiomZTEuoJ6MOxsGK2w==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
employeeID: thoupt
badPasswordTime: 132293872471850639
lastLogoff: 0
lastLogon: 132293873040455889
pwdLastSet: 132224505785793976
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAxrtQevGzEnEH5Tsrr1MCAA==
accountExpires: 9223372036854775807
logonCount: 381
sAMAccountName: thoupt
sAMAccountType: 805306368
showInAddressBook: CN=Default Global Address List,CN=All Global Address Lists,
CN=Address Lists Container,CN=Florida State University,CN=Microsoft Exchange,
CN=Services,CN=Configuration,DC=fsu,DC=edu
legacyExchangeDN: /o=Florida State University/ou=External (FYDIBOHF25SPDLT)/cn
=Recipients/cn=72ed2cb119d94ddfa76761a152fc06d3
userPrincipalName: thoupt@fsu.edu
lockoutTime: 0
url: http://images.its.fsu.edu/fsucardimages/small/EYO793C3.JPG
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=fsu,DC=edu
dSCorePropagationData: 20190814195208.0Z
dSCorePropagationData: 20190814192329.0Z
dSCorePropagationData: 20190718213701.0Z
dSCorePropagationData: 20190709173154.0Z
dSCorePropagationData: 16010714223649.0Z
lastLogonTimestamp: 132300899324520618
textEncodedORAddress: X400:C=US;A= ;P=Florida State Un;O=OLYMPUS;S=Houpt;G=Tho
mas;
mail: houpt@neuro.fsu.edu
manager: CN=shuckaba,OU=Arts and Sciences,OU=FSU-Dept-Accounts,DC=fsu,DC=edu
msExchALObjectVersion: 126
msExchUserAccountControl: 0
msExchMailboxGuid:: jVNvfEByRE28mpKEw8cTug==
msExchPoliciesExcluded: {26491cfc-9e50-4857-861b-0cb8df22b5d7}
msExchVersion: 44220983382016
fsuEduAffiliation: 9_10MONTH,EMPLOYEE,FACULTY
fsuEduAffiliations: FACULTY
fsuEduAffiliations: 9_10MONTH
fsuEduAffiliations: EMPLOYEE
msExchUMDtmfMap: reversedPhone:4244446058
msExchUMDtmfMap: emailAddress:46878
msExchUMDtmfMap: lastNameFirstName:46878846627
msExchUMDtmfMap: firstNameLastName:84662746878
msExchRecipientDisplayType: -2147483642
msExchRecipientTypeDetails: 2147483648
msExchUserHoldPolicies: 98E9BABD09A04bcf8455A58C2AA74182Unlimit
sharePointProfileStatus: Yes
fsuEduEMPLID: 000024253
fsuEduAppRoles: CS_ADMN_STDT_CNT
fsuEduAppRoles: CS_CC_STUVIEW
msExchTextMessagingState: 302120705
msExchTextMessagingState: 16842751
msExchWhenMailboxCreated: 20111222220740.0Z
msExchRemoteRecipientType: 4
# refldap://mscloud.fsu.edu/DC=mscloud,DC=fsu,DC=edu
# refldap://fsu.edu/CN=Configuration,DC=fsu,DC=edu
# refldap://ForestDnsZones.fsu.edu/DC=ForestDnsZones,DC=fsu,DC=edu
# refldap://DomainDnsZones.fsu.edu/DC=DomainDnsZones,DC=fsu,DC=edu
*/
if (typeof ldap_cache[emplid] != "undefined") {
return ldap_cache[emplid];
}
let ldap_args = [
'-L', '-L', '-L',
'-h', 'fsu-dc-1.fsu.edu',
'-D', username + '@fsu.edu', //doesn't need to be in quotes if using execFileSync
'-w', password, '-b',
'dc=fsu,dc=edu', //doesn't need to be in quotes if using execFileSync
'-s', 'sub',
'fsuEduEMPLID=' + emplid.toString().padStart(9, '0'), //doesn't need to be in quotes if using execFileSync
'employeeID',
'mail',
'department',
'url',
'givenName'
];
var ldap_results = execFileSync("ldapsearch", ldap_args, []); // execFile
// console.log(ldap_results.toString('utf8'));
if (ldap_results.toString('utf8').match(fsuid_regex) == null) {
console.log(emplid + ": no fsuid found!");
//so use emplid
return emplid;
}
var fsuid_match = ldap_results.toString('utf8').match(fsuid_regex);
var email_match = ldap_results.toString('utf8').match(email_regex);
var dept_match = ldap_results.toString('utf8').match(dept_regex);
var photo_match = ldap_results.toString('utf8').match(photo_regex);
var given_match = ldap_results.toString('utf8').match(given_regex);
var fsuid = (fsuid_match != null) ? fsuid_match[1].trim() : null;
var email = (email_match != null) ? email_match[1].trim() : null;
var dept = (dept_match != null) ? dept_match[1].trim() : null;
var photo_url = (photo_match != null) ? photo_match[1].trim() : null;
var given = (given_match != null) ? given_match[1].trim() : null;
// sometimes employeeID is set to emplid, not fsuid...
// so find from first line, "dn: CN=<fsuid>"
if (parseInt(fsuid, 10) == emplid) {
fsuid = ldap_results.toString('utf8').match(CN_regex)[1];
}
//console.log("found " + emplid.toString().padStart(9,'0') + ": " + fsuid);
// cache so we don't have to look up again
var ldap_info = {
"fsuid": fsuid,
"email": email,
"department": dept,
"photo_url": photo_url,
"givenName": given
};
ldap_cache[emplid] = ldap_info;
// before update ldap_cache on disk, make sure we have a created date field
if (!fs.existsSync(__dirname + "/_ldap_cache_started.json")) {
let time_now = Date.now();
let ldap_cache_started = {"timestamp" : time_now };
fs.writeFileSync(__dirname + "/_ldap_cache_started.json", JSON.stringify(ldap_cache_started));
}
fs.writeFileSync(__dirname + "/_ldap_cache.json", JSON.stringify(ldap_cache));
return ldap_info;
}
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
module.exports = {
initializeFromCSVPathWithKey: initializeFromCSVPathWithKey,
initializeFromYAMLPath: initializeFromYAMLPath,
writeUpdateFile: writeUpdateFile,
getDatetimeString,
backupFile: backupFile,
deepCopy: deepCopy,
readJSON: readJSON,
readJSONfromCWD: readJSONfromCWD,
readJSONfromAppDir: readJSONfromAppDir,
isUndefined: isUndefined,
isNull: isNull,
isUndefinedOrIsNull: isUndefinedOrIsNull,
isUndefinedOrIsNullParentAndChild,
notUndefinedAndNotNullParentAndChild,
notUndefined: notUndefined,
notNull: notNull,
notUndefinedAndNotNull: notUndefinedAndNotNull,
isEmptyObject: isEmptyObject,
removeInvalidKeysFromObject: removeInvalidKeysFromObject,
removeInvalidKeysFromObjectDebug: removeInvalidKeysFromObjectDebug,
getLDAPInfo: getLDAPInfo
};