exports.addRacUsers = async (req, res) => {
try {
// bring fixes from staging to generate credential
// add column with ScrumLab session ids to xls
// convert xls to csv
// use https://www.papaparse.com/ to parse csv into json
const readCSVFile = async () => {
const file = fs.readFileSync('test_RAC.csv');
const data = file.toString();
return new Promise((resolve) => {
papaparse.parse(data, {
header: true,
complete: (results) => {
resolve(results.data);
},
});
});
};
// https://www.30secondsofcode.org/js/s/group-by?from=autocomplete
const groupBy = (arr, fn) =>
arr
.map(typeof fn === 'function' ? fn : (val) => val[fn])
.reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
const jsonData = await readCSVFile();
// we are grouping the array by sessionId so that
// we only need to fetch the session once per session as we iterate through the
// students in that session
const groupedBySessionIds = groupBy(jsonData, 'sessionId');
for (const [sessionId, rows] of Object.entries(groupedBySessionIds)) {
const session = await Session.findById(sessionId);
if (!session) {
console.log(sessionId, ' sessionId does not exist');
continue;
}
const achievementDate = moment('2022-01-31');
const achievementDateSince = moment(session.date_end);
const achievementDateExpires = moment('2023-01-23');
for (const row of rows) {
// find user to check if they exist in ScrumLab
const existingUser = await User.findOne({
username: row['Email Address'],
}).populate({
path: 'sessions',
select: '_id courses',
populate: { path: 'courses', select: 'name' },
});
if (existingUser) {
const existingAchievementIndex = existingUser.achievements.findIndex(
({ name }) => name === 'Registered Agile Coach'
);
const existingAchievement =
existingUser.achievements[existingAchievementIndex];
// if the user has the achievement and it is already linked to a session
// we can skip this user
if (existingAchievementIndex > -1 && existingAchievement.session) {
continue;
}
// if the use has the achievement but it's not linked to a session
if (existingAchievementIndex > -1 && !existingAchievement.session) {
// if it does NOT have a session, add the user to the RAC session and update the achievement to link to the session
const hasExistingRACSession = existingUser.sessions.find(
({ courses }) => courses[0]?.name.includes('Agile Coach')
);
if (hasExistingRACSession) {
// update achievement linking to session
existingUser.achievements[existingAchievementIndex].session =
hasExistingRACSession;
existingUser.markModified('achievements');
await existingUser.save();
continue;
}
// adding to the session if the user does not have the session or the session does not have user
const userHasSession =
existingUser.sessions.findIndex(
({ _id }) => _id.toString() === session._id.toString()
) > -1;
const sessionHasUser =
session.users.findIndex(
(u) => u.toString() === existingUser._id.toString()
) > -1;
if (!userHasSession) {
existingUser.sessions.push(session);
}
if (!sessionHasUser) {
session.users.push(existingUser);
}
// updating achievement linking to session
existingUser.achievements[existingAchievementIndex].session =
session;
existingUser.markModified('achievements');
await existingUser.save();
} else {
// if they don't have the achievement, add them to the session and add the achievement (linking to session)
const userHasSession =
existingUser.sessions.findIndex(
({ _id }) => _id.toString() === session._id.toString()
) > -1;
const sessionHasUser =
session.users.findIndex(
(u) => u.toString() === existingUser._id.toString()
) > -1;
if (!userHasSession) {
existingUser.sessions.push(session);
}
if (!sessionHasUser) {
session.users.push(existingUser);
}
const achievement = {
session,
name: 'Registered Agile Coach',
date: achievementDate,
date_since: achievementDateSince,
date_expires: achievementDateExpires,
cert_url: '',
cert_id: '',
renewal_stage: 1,
cert_path: 'rac.dox',
subachievements: [],
};
const [err, certUrl, certId] = await generateCredential({
achName: 'Registered Agile Coach',
user: existingUser,
dateSince: achievement.date_since,
certTemplate: 'rac.docx',
dateExpires: achievement.date_expires,
});
if (err) {
console.log('error generating cred for ', existingUser.username);
continue;
}
achievement.cert_url = certUrl;
achievement.cert_id = certId;
existingUser.achievements.push(achievement);
await existingUser.save();
}
// prepare and send the email for existing users indicating they got added to the session
strings.setLanguage(existingUser.language || 'en');
const template = require('../templates/add_user_existing')(strings);
const htmlOutput = mjml2html(template);
const html = htmlOutput.html
.replace(
'{{first_name}}',
existingUser.first_name ? existingUser.first_name : ''
)
.replace('{{class_name}}', session.name);
// todo: uncomment when we're ready to run with prod data
// generateEmail(
// existingUser.username,
// `${session.name} has been added to your ScrumLab Account`,
// html
// );
} else {
// if user does not exist:
// parse user data in order to create a new user
const nameArray = row['Name'].split(' ');
let firstName;
let lastName;
if (nameArray.length === 2) {
firstName = nameArray[0];
lastName = nameArray[1];
} else {
console.log(row['Name']);
if (nameArray[nameArray.length - 2].length < 3) {
lastName = nameArray.splice(nameArray.length - 2, 2).join(' ');
firstName = nameArray.join(' ');
} else {
lastName = nameArray.pop();
firstName = nameArray.join(' ');
}
}
console.log(firstName, lastName);
const data = {
first_name: firstName,
last_name: lastName,
username: row['Email Address'],
full_name: row['Name'],
};
// create the user, generate pw, and set partner
const newUser = new User(data);
newUser.partner = session.partner;
const password = newUser.generatePassword();
// add session to user, and add user to session
const userHasSession =
newUser.sessions.findIndex(
({ _id }) => _id.toString() === session._id.toString()
) > -1;
const sessionHasUser =
session.users.findIndex(
(u) => u.toString() === newUser._id.toString()
) > -1;
if (!userHasSession) {
newUser.sessions.push(session);
}
if (!sessionHasUser) {
session.users.push(newUser);
}
// add the achievement
const achievement = {
session,
name: 'Registered Agile Coach',
date: achievementDate,
date_since: achievementDateSince,
date_expires: achievementDateExpires,
cert_url: '',
cert_id: '',
renewal_stage: 1,
cert_path: 'rac.dox',
subachievements: [],
};
const [err, certUrl, certId] = await generateCredential({
achName: 'Registered Agile Coach',
user: newUser,
dateSince: achievement.date_since,
certTemplate: 'rac.docx',
dateExpires: achievement.date_expires,
});
if (err) {
console.log('error generating cred for ', newUser.username);
continue;
}
achievement.cert_url = certUrl;
achievement.cert_id = certId;
newUser.achievements.push(achievement);
await newUser.save();
// prepare and send email for NEW users with their login info
strings.setLanguage(newUser.language || 'en');
const template = require('../../templates/add_user_new')(strings);
const htmlOutput = mjml2html(template);
const html = htmlOutput.html
.replace(
'{{first_name}}',
newUser.first_name ? newUser.first_name : ''
)
.replace('{{username}}', newUser.username)
.replace('{{password}}', password);
// todo: uncomment when we're ready to run with prod data
// generateEmail(newUser.username, `ScrumLab login information`, html);
}
}
await session.save();
}
// TEST agaisnt dev DB
// DONE update emails to include Alex in signature
// reviewed by Reiner and Larsen before running
res.status(200).send('OK');
} catch (err) {
return res.status(500).json({ message: err.message });
}
};