diff --git a/src/.env.sample b/src/.env.sample
index da4e42b3e..35d04d684 100644
--- a/src/.env.sample
+++ b/src/.env.sample
@@ -182,3 +182,6 @@ SCHEDULER_SERVICE_BASE_URL= '/scheduler/'
#Refresh interval for materialized views
REFRESH_VIEW_INTERVAL= 540000
+
+#Generic Email template for new users
+GENERIC_INVITATION_EMAIL_TEMPLATE_CODE=generic_invite
diff --git a/src/constants/common.js b/src/constants/common.js
index 84b729162..cb67b64a6 100644
--- a/src/constants/common.js
+++ b/src/constants/common.js
@@ -95,6 +95,7 @@ module.exports = {
INACTIVE_STATUS: 'INACTIVE',
MENTOR_ROLE: 'mentor',
MENTEE_ROLE: 'mentee',
+ SESSION_MANAGER_ROLE: 'session_manager',
redisUserPrefix: 'user_',
redisOrgPrefix: 'org_',
location: 'location',
@@ -120,4 +121,5 @@ module.exports = {
materializedViewsPrefix: 'm_',
DELETED_STATUS: 'DELETED',
DEFAULT_ORG_VISIBILITY: 'PUBLIC',
+ ROLE_TYPE_NON_SYSTEM: 0,
}
diff --git a/src/database/migrations/20240122091311-create-generic-invitation-template.js b/src/database/migrations/20240122091311-create-generic-invitation-template.js
new file mode 100644
index 000000000..78ba2a30f
--- /dev/null
+++ b/src/database/migrations/20240122091311-create-generic-invitation-template.js
@@ -0,0 +1,32 @@
+'use strict'
+const moment = require('moment')
+
+/** @type {import('sequelize-cli').Migration} */
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ const defaultOrgId = queryInterface.sequelize.options.defaultOrgId
+ if (!defaultOrgId) {
+ throw new Error('Default org ID is undefined. Please make sure it is set in sequelize options.')
+ }
+ let notificationTemplateData = [
+ {
+ code: 'generic_invite',
+ subject: 'Welcome Aboard as a {roles}',
+ body: '
Dear {name},
We are delighted to inform you that you have been successfully onboarded as a {roles} for {orgName}. You can now explore {appName}.
We request you to register on our Mentoring Platform (if not already), to start your journey with us as a organization admin.
Click to register: {portalURL}',
+ status: 'ACTIVE',
+ type: 'email',
+ created_at: moment().format(),
+ updated_at: moment().format(),
+ email_header: 'email_header',
+ email_footer: 'email_footer',
+ organization_id: defaultOrgId,
+ },
+ ]
+
+ await queryInterface.bulkInsert('notification_templates', notificationTemplateData, {})
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ await queryInterface.bulkDelete('notification_templates', { code: 'generic_invite' })
+ },
+}
diff --git a/src/database/migrations/20240122092217-update-registration-template.js b/src/database/migrations/20240122092217-update-registration-template.js
new file mode 100644
index 000000000..1a3d6ad31
--- /dev/null
+++ b/src/database/migrations/20240122092217-update-registration-template.js
@@ -0,0 +1,42 @@
+'use strict'
+
+/** @type {import('sequelize-cli').Migration} */
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ const defaultOrgId = queryInterface.sequelize.options.defaultOrgId
+ if (!defaultOrgId) {
+ throw new Error('Default org ID is undefined. Please make sure it is set in sequelize options.')
+ }
+ const registrationTemplate = await queryInterface.sequelize.query(
+ `SELECT * FROM notification_templates WHERE code = :code AND organization_id = :organization_id LIMIT 1`,
+ {
+ replacements: {
+ code: process.env.REGISTRATION_EMAIL_TEMPLATE_CODE,
+ organization_id: defaultOrgId,
+ },
+ type: Sequelize.QueryTypes.SELECT,
+ }
+ )
+
+ if (registrationTemplate) {
+ const update = await queryInterface.sequelize.query(
+ `UPDATE notification_templates SET body = :body WHERE code = :code AND organization_id = :organization_id`,
+ {
+ replacements: {
+ code: process.env.REGISTRATION_EMAIL_TEMPLATE_CODE,
+ organization_id: defaultOrgId,
+ body: 'Dear {name},
Welcome to {appName} community! . We are excited for you to start your journey as a {roles}.
Login to MentorED to start your journey
Click to register: {portalURL}',
+ },
+ type: Sequelize.QueryTypes.UPDATE,
+ }
+ )
+ console.log(update, 'update')
+ } else {
+ console.log('Registration template not found')
+ }
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ //not required
+ },
+}
diff --git a/src/database/queries/orgUserInvite.js b/src/database/queries/orgUserInvite.js
index ce812b53e..eebed553a 100644
--- a/src/database/queries/orgUserInvite.js
+++ b/src/database/queries/orgUserInvite.js
@@ -1,6 +1,6 @@
'use strict'
const organizationUserInvite = require('../models/index').OrganizationUserInvite
-const { UniqueConstraintError, ValidationError } = require('sequelize')
+const { ValidationError } = require('sequelize')
exports.create = async (data) => {
try {
diff --git a/src/database/queries/userCredential.js b/src/database/queries/userCredential.js
index e941f4f4c..64a724af7 100644
--- a/src/database/queries/userCredential.js
+++ b/src/database/queries/userCredential.js
@@ -1,5 +1,6 @@
'use strict'
const UserCredential = require('@database/models/index').UserCredential
+const { UniqueConstraintError, ValidationError } = require('sequelize')
exports.create = async (data) => {
try {
@@ -7,7 +8,7 @@ exports.create = async (data) => {
return res.get({ plain: true })
} catch (error) {
if (error instanceof UniqueConstraintError) {
- return 'USER_ALREADY_EXISTS'
+ return 'User already exist'
} else if (error instanceof ValidationError) {
let message
error.errors.forEach((err) => {
diff --git a/src/envVariables.js b/src/envVariables.js
index fbcc51fac..44d5f78da 100644
--- a/src/envVariables.js
+++ b/src/envVariables.js
@@ -252,6 +252,10 @@ let enviromentVariables = {
optional: false,
default: 'aes-256-cbc',
},
+ GENERIC_INVITATION_EMAIL_TEMPLATE_CODE: {
+ message: 'Required generic invitation email template code',
+ optional: false,
+ },
}
let success = true
diff --git a/src/generics/utils.js b/src/generics/utils.js
index bf97d2bbf..df2658c34 100644
--- a/src/generics/utils.js
+++ b/src/generics/utils.js
@@ -423,6 +423,13 @@ const generateWhereClause = (tableName) => {
return whereClause
}
+const getRoleTitlesFromId = (roleIds = [], roleList = []) => {
+ return roleIds.map((roleId) => {
+ const role = roleList.find((r) => r.id === roleId)
+ return role ? role.title : null
+ })
+}
+
module.exports = {
generateToken,
hashPassword,
@@ -452,4 +459,5 @@ module.exports = {
isValidEmail,
isValidName,
generateWhereClause,
+ getRoleTitlesFromId,
}
diff --git a/src/sample.csv b/src/sample.csv
index 98b1e86ee..f1c308291 100644
--- a/src/sample.csv
+++ b/src/sample.csv
@@ -1,3 +1,4 @@
name,email,roles
Sarah,sarah@tunerlabs.com,mentee
John,john@tunerlabs.com,mentor
+Pradeep,pradeep@tunerlabs.com,"mentor,session_manager"
diff --git a/src/services/account.js b/src/services/account.js
index d7a363551..0b33be187 100644
--- a/src/services/account.js
+++ b/src/services/account.js
@@ -104,7 +104,7 @@ module.exports = class AccountHelper {
if (invitedUserMatch) {
bodyData.organization_id = invitedUserMatch.organization_id
roles = invitedUserMatch.roles
- role = await roleQueries.findOne(
+ role = await roleQueries.findAll(
{ id: invitedUserMatch.roles },
{
attributes: {
@@ -113,7 +113,7 @@ module.exports = class AccountHelper {
}
)
- if (!role) {
+ if (!role.length > 0) {
return common.failureResponse({
message: 'ROLE_NOT_FOUND',
statusCode: httpStatusCode.not_acceptable,
@@ -121,20 +121,21 @@ module.exports = class AccountHelper {
})
}
- if (role.title === common.ORG_ADMIN_ROLE) {
- isOrgAdmin = true
-
- const defaultRole = await roleQueries.findOne(
- { title: process.env.DEFAULT_ROLE },
- {
- attributes: {
- exclude: ['created_at', 'updated_at', 'deleted_at'],
- },
- }
- )
+ role.forEach(async (eachRole) => {
+ if (eachRole.title === common.ORG_ADMIN_ROLE) {
+ const defaultRole = await roleQueries.findOne(
+ { title: process.env.DEFAULT_ROLE },
+ {
+ attributes: {
+ exclude: ['created_at', 'updated_at', 'deleted_at'],
+ },
+ }
+ )
- roles.push(defaultRole.id)
- }
+ roles.push(defaultRole.id)
+ isOrgAdmin = true
+ }
+ })
bodyData.roles = roles
} else {
//find organization from email domain
@@ -234,6 +235,23 @@ module.exports = class AccountHelper {
user.user_roles = roleData
+ // format the roles for email template
+ let roleArray = []
+ if (roleData.length > 0) {
+ const mentorRoleExists = roleData.some((role) => role.title === common.MENTOR_ROLE)
+ if (mentorRoleExists) {
+ const updatedRoleList = roleData.filter((role) => role.title !== common.MENTEE_ROLE)
+ roleArray = _.map(updatedRoleList, 'title')
+ }
+ }
+
+ let roleToString =
+ roleArray.length > 0
+ ? roleArray
+ .map((role) => role.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()))
+ .join(' and ')
+ : ''
+
const accessToken = utilsHelper.generateToken(
tokenDetail,
process.env.ACCESS_TOKEN_SECRET,
@@ -290,6 +308,8 @@ module.exports = class AccountHelper {
body: utilsHelper.composeEmailBody(templateData.body, {
name: bodyData.name,
appName: process.env.APP_NAME,
+ roles: roleToString || '',
+ portalURL: process.env.PORTAL_URL,
}),
},
}
diff --git a/src/services/org-admin.js b/src/services/org-admin.js
index ef583ddb2..c53e5e5b8 100644
--- a/src/services/org-admin.js
+++ b/src/services/org-admin.js
@@ -55,6 +55,7 @@ module.exports = class OrgAdminHelper {
}
const result = await fileUploadQueries.create(creationData)
+
if (!result?.id) {
return common.successResponse({
responseCode: 'CLIENT_ERROR',
@@ -421,12 +422,6 @@ function updateRoleForApprovedRequest(requestDetails, user) {
{ attributes: ['title', 'id', 'user_type', 'status'] }
)
- const systemRoleIds = userRoles
- .filter((role) => role.user_type === common.ROLE_TYPE_SYSTEM)
- .map((role) => role.id)
-
- let rolesToUpdate = [...systemRoleIds]
-
const newRole = await roleQueries.findOne(
{ id: requestDetails.role, status: common.ACTIVE_STATUS },
{ attributes: ['title', 'id', 'user_type', 'status'] }
@@ -440,7 +435,16 @@ function updateRoleForApprovedRequest(requestDetails, user) {
},
})
- rolesToUpdate.push(requestDetails.role)
+ let rolesToUpdate = [...requestDetails.role]
+ let currentUserRoleIds = _.map(userRoles, 'id')
+
+ //remove mentee role from roles array
+ const menteeRoleId = userRoles.find((role) => role.title === common.MENTEE_ROLE)?.id
+ if (menteeRoleId && currentUserRoleIds.includes(menteeRoleId)) {
+ _.pull(currentUserRoleIds, menteeRoleId)
+ }
+ rolesToUpdate.push(...currentUserRoleIds)
+
const roles = _.uniq(rolesToUpdate)
await userQueries.updateUser(
diff --git a/src/services/userInvite.js b/src/services/userInvite.js
index 782368ce4..816912c6c 100644
--- a/src/services/userInvite.js
+++ b/src/services/userInvite.js
@@ -42,7 +42,6 @@ module.exports = class UserInviteHelper {
// extract data from csv
const parsedFileData = await this.extractDataFromCSV(response.result.downloadPath)
if (!parsedFileData.success) throw new Error('FAILED_TO_READ_CSV')
-
const invitees = parsedFileData.result.data
// create outPut file and create invites
@@ -51,8 +50,8 @@ module.exports = class UserInviteHelper {
// upload output file to cloud
const uploadRes = await this.uploadFileToCloud(outputFilename, inviteeFileDir, data.user.id)
-
const output_path = uploadRes.result.uploadDest
+
const update = {
output_path,
updated_by: data.user.id,
@@ -60,7 +59,7 @@ module.exports = class UserInviteHelper {
createResponse.result.isErrorOccured == true ? common.FAILED_STATUS : common.PROCESSED_STATUS,
}
- // //update output path in file uploads
+ //update output path in file uploads
const rowsAffected = await fileUploadQueries.update(
{ id: data.fileDetails.id, organization_id: data.user.organization_id },
update
@@ -69,7 +68,7 @@ module.exports = class UserInviteHelper {
throw new Error('FILE_UPLOAD_MODIFY_ERROR')
}
- // // send email to admin
+ // send email to admin
const templateCode = process.env.ADMIN_INVITEE_UPLOAD_EMAIL_TEMPLATE_CODE
if (templateCode) {
const templateData = await notificationTemplateQueries.findOneEmailTemplate(
@@ -92,6 +91,7 @@ module.exports = class UserInviteHelper {
message: 'CSV_UPLOADED_SUCCESSFULLY',
})
} catch (error) {
+ console.log(error, 'CSV PROCESSING ERROR')
return reject({
success: false,
message: error.message,
@@ -139,6 +139,15 @@ module.exports = class UserInviteHelper {
static async extractDataFromCSV(csvFilePath) {
try {
const csvToJsonData = await csv().fromFile(csvFilePath)
+ const header = Object.keys(csvToJsonData[0])
+
+ if (header.map((column) => column.toLowerCase()).includes('roles')) {
+ // Process the data, split roles, and handle unquoted roles
+ csvToJsonData.forEach((row) => {
+ const roles = row.roles.replace(/"/g, '').split(',')
+ row.roles = roles
+ })
+ }
return {
success: true,
result: {
@@ -156,30 +165,46 @@ module.exports = class UserInviteHelper {
static async createUserInvites(csvData, user, fileUploadId) {
try {
const outputFileName = utils.generateFileName(common.inviteeOutputFile, common.csvExtension)
- const allRoles = _.uniq(_.map(csvData, 'roles').map((role) => role.toLowerCase()))
- const roleList = await roleQueries.findAll({ title: allRoles })
+ let menteeRoleId, mentorRoleId
+
+ //get all the roles and map title and id
+ const roleList = await roleQueries.findAll({
+ user_type: common.ROLE_TYPE_NON_SYSTEM,
+ status: common.ACTIVE_STATUS,
+ })
const roleTitlesToIds = {}
roleList.forEach((role) => {
roleTitlesToIds[role.title] = [role.id]
+ if (role.title === common.MENTEE_ROLE) {
+ menteeRoleId = role.id
+ }
+ if (role.title === common.MENTOR_ROLE) {
+ mentorRoleId = role.id
+ }
})
//get all existing user
const emailArray = _.uniq(_.map(csvData, 'email')).map((email) =>
emailEncryption.encrypt(email.toLowerCase())
)
+
const userCredentials = await UserCredentialQueries.findAll(
{ email: { [Op.in]: emailArray } },
{
- attributes: ['user_id'],
+ attributes: ['user_id', 'email'],
}
- ) //This is valid since UserCredentials Already Store The Encrypted Email ID
+ )
+
+ //This is valid since UserCredentials Already Store The Encrypted Email ID
const userIds = _.map(userCredentials, 'user_id')
const existingUsers = await userQueries.findAll(
{ id: userIds },
{
attributes: ['id', 'email', 'organization_id', 'roles'],
}
- ) //Get All The Users From Database based on UserIds From UserCredentials
+ )
+
+ //Get All The Users From Database based on UserIds From UserCredentials
const existingEmailsMap = new Map(existingUsers.map((eachUser) => [eachUser.email, eachUser])) //Figure Out Who Are The Existing Users
//find default org id
@@ -190,24 +215,13 @@ module.exports = class UserInviteHelper {
let isErrorOccured = false
let isOrgUpdate = false
- //fetch email template
- const mentorTemplateCode = process.env.MENTOR_INVITATION_EMAIL_TEMPLATE_CODE || null
- const menteeTemplateCode = process.env.MENTEE_INVITATION_EMAIL_TEMPLATE_CODE || null
-
- const [mentorTemplateData, menteeTemplateData] = await Promise.all([
- mentorTemplateCode
- ? notificationTemplateQueries.findOneEmailTemplate(mentorTemplateCode, user.organization_id)
- : null,
- menteeTemplateCode
- ? notificationTemplateQueries.findOneEmailTemplate(menteeTemplateCode, user.organization_id)
- : null,
- ])
-
- const templates = {
- [common.MENTOR_ROLE]: mentorTemplateData,
- [common.MENTEE_ROLE]: menteeTemplateData,
- }
+ //fetch generic email template
+ const emailTemplate = await notificationTemplateQueries.findOneEmailTemplate(
+ process.env.GENERIC_INVITATION_EMAIL_TEMPLATE_CODE,
+ user.organization_id
+ )
+ //find already invited users
const emailList = await userInviteQueries.findAll({ email: emailArray })
const existingInvitees = {}
emailList.forEach((userInvitee) => {
@@ -216,43 +230,59 @@ module.exports = class UserInviteHelper {
// process csv data
for (const invitee of csvData) {
- //convert the fields to lower case
- invitee.roles = invitee.roles.toLowerCase()
invitee.email = invitee.email.toLowerCase()
const encryptedEmail = emailEncryption.encrypt(invitee.email.toLowerCase())
- //validate the fields
+ //find the invalid fields and generate error message
+ let invalidFields = []
if (!utils.isValidName(invitee.name)) {
- invitee.statusOrUserId = 'NAME_INVALID'
- input.push(invitee)
- continue
+ invalidFields.push('name')
}
-
if (!utils.isValidEmail(invitee.email)) {
- invitee.statusOrUserId = 'EMAIL_INVALID'
- input.push(invitee)
- continue
+ invalidFields.push('email')
+ }
+
+ const invalidRoles = invitee.roles.filter((role) => !roleTitlesToIds.hasOwnProperty(role.toLowerCase()))
+ if (invalidRoles.length > 0) {
+ invalidFields.push('roles')
}
- if (!roleTitlesToIds.hasOwnProperty(invitee.roles)) {
- invitee.statusOrUserId = 'ROLE_INVALID'
+ //merge all error message
+ if (invalidFields.length > 0) {
+ const errorMessage = `${
+ invalidFields.length > 2
+ ? invalidFields.slice(0, -1).join(', ') + ', and ' + invalidFields.slice(-1)
+ : invalidFields.join(' and ')
+ } ${invalidFields.length > 1 ? 'are' : 'is'} invalid.`
+
+ invitee.statusOrUserId = errorMessage
+ invitee.roles = invitee.roles.length > 0 ? invitee.roles.join(',') : ''
input.push(invitee)
continue
}
- //update user details if the user exist and in default org
const existingUser = existingEmailsMap.get(encryptedEmail)
+ //return error for already invited user
+ if (!existingUser && existingInvitees.hasOwnProperty(encryptedEmail)) {
+ invitee.statusOrUserId = 'User already exist'
+ invitee.roles = invitee.roles.length > 0 ? invitee.roles.join(',') : ''
+ input.push(invitee)
+ continue
+ }
+ // Update user details if the user exists and belongs to the default organization
if (existingUser) {
- invitee.statusOrUserId = 'USER_ALREADY_EXISTS'
+ invitee.statusOrUserId = 'User already exist'
isErrorOccured = true
const isOrganizationMatch =
existingUser.organization_id === defaultOrgId ||
existingUser.organization_id === user.organization_id
+
if (isOrganizationMatch) {
let userUpdateData = {}
+ //update user organization
if (existingUser.organization_id != user.organization_id) {
await userQueries.changeOrganization(
existingUser.id,
@@ -262,23 +292,44 @@ module.exports = class UserInviteHelper {
organization_id: user.organization_id,
}
)
+
isOrgUpdate = true
userUpdateData.refresh_tokens = []
}
- const areAllElementsInArray = _.every(roleTitlesToIds[invitee.roles], (element) =>
- _.includes(existingUser.roles, element)
+
+ //find the new roles
+ const elementsNotInArray = _.difference(
+ _.map(invitee.roles, (role) => roleTitlesToIds[role.toLowerCase()]).flat(),
+ existingUser.roles
)
- if (!areAllElementsInArray) {
- userUpdateData.roles = roleTitlesToIds[invitee.roles]
+
+ //update the user roles and handle downgrade of role
+ if (elementsNotInArray.length > 0) {
+ userUpdateData.roles = []
+ if (existingUser.roles.includes(menteeRoleId)) {
+ if (existingUser.roles.length === 1) {
+ userUpdateData.roles.push(...elementsNotInArray, menteeRoleId)
+ } else {
+ userUpdateData.roles.push(...elementsNotInArray, ...existingUser.roles)
+ }
+ } else {
+ userUpdateData.roles.push(...elementsNotInArray, ...existingUser.roles)
+ }
+
+ if (userUpdateData.roles.includes(mentorRoleId)) {
+ userUpdateData.roles = _.pull(userUpdateData.roles, menteeRoleId)
+ }
+
userUpdateData.refresh_tokens = []
}
+ //update user and user credentials table with new role organization
if (isOrgUpdate || userUpdateData.roles) {
- const userCredentials = await UserCredentialQueries.findOne({
+ const userCred = await UserCredentialQueries.findOne({
email: encryptedEmail,
})
- await userQueries.updateUser({ id: userCredentials.user_id }, userUpdateData)
+ await userQueries.updateUser({ id: userCred.user_id }, userUpdateData)
await UserCredentialQueries.updateUser(
{
email: encryptedEmail,
@@ -286,70 +337,100 @@ module.exports = class UserInviteHelper {
{ organization_id: user.organization_id }
)
- const userRoles = await roleQueries.findAll({ id: existingUser.roles })
- //call event to update in mentoring
- if (!userUpdateData?.roles) {
+ const currentRoles = utils.getRoleTitlesFromId(existingUser.roles, roleList)
+ let newRoles = []
+ newRoles = utils.getRoleTitlesFromId(
+ _.difference(userUpdateData.roles, existingUser.roles),
+ roleList
+ )
+ //remove session_manager role because the mentee role is enough to change role in mentoring side
+ newRoles = newRoles.filter((role) => role !== common.SESSION_MANAGER_ROLE)
+
+ //call event to update organization in mentoring
+ if (isOrgUpdate) {
eventBroadcaster('updateOrganization', {
requestBody: {
user_id: existingUser.id,
organization_id: user.organization_id,
- roles: _.map(userRoles, 'title'),
+ roles: currentRoles,
},
})
- } else {
+ }
+
+ if (newRoles.length > 0) {
+ //call event to update role and organization in mentoring
let requestBody = {
user_id: existingUser.id,
- new_roles: [invitee.roles],
- current_roles: _.map(userRoles, 'title'),
+ new_roles: newRoles,
+ current_roles: currentRoles,
}
if (isOrgUpdate) requestBody.organization_id = user.organization_id
eventBroadcaster('roleChange', {
requestBody,
})
}
+
+ //remove user data from redis
const redisUserKey = common.redisUserPrefix + existingUser.id.toString()
await utils.redisDel(redisUserKey)
+ invitee.statusOrUserId = 'success'
+ } else {
+ invitee.statusOrUserId = 'No updates needed. User details are already up to date'
}
+ } else {
+ //user doesn't have access to update user data
+ invitee.statusOrUserId = 'Unauthorized to update user details in a different organization.'
}
} else {
+ //new user invitee creation
const inviteeData = {
...invitee,
status: common.UPLOADED_STATUS,
organization_id: user.organization_id,
file_id: fileUploadId,
- roles: roleTitlesToIds[invitee.roles] || [],
- }
- inviteeData.email = encryptedEmail
-
- if (existingInvitees.hasOwnProperty(encryptedEmail)) {
- invitee.statusOrUserId = 'USER_ALREADY_EXISTS'
- input.push(invitee)
- continue
+ roles: (invitee.roles || []).map((roleTitle) => roleTitlesToIds[roleTitle.toLowerCase()] || []),
+ email: encryptedEmail,
}
+ inviteeData.email = encryptedEmail
const newInvitee = await userInviteQueries.create(inviteeData)
- if (newInvitee.id) {
+
+ if (newInvitee?.id) {
+ console.log(newInvitee.roles, 'newInvitee.roles')
invitee.statusOrUserId = newInvitee.id
+
+ //create user credentials entry
const newUserCred = await UserCredentialQueries.create({
email: newInvitee.email,
organization_id: newInvitee.organization_id,
organization_user_invite_id: newInvitee.id,
})
- if (newUserCred.id) {
- const { name, email, roles } = invitee
+
+ if (newUserCred?.id) {
+ const { name, email } = invitee
+ const roles = utils.getRoleTitlesFromId(newInvitee.roles, roleList)
+ const roleToString =
+ roles.length > 0
+ ? roles
+ .map((role) =>
+ role.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
+ )
+ .join(' and ')
+ : ''
+
const userData = {
name,
email,
- role: roles,
+ role: roleToString,
org_name: user.org_name,
}
- const templateData = templates[roles]
- //send email invitation for user
- if (templateData && Object.keys(templateData).length > 0) {
- await this.sendInviteeEmail(templateData, userData)
+ //send email invitation for new user
+ if (emailTemplate) {
+ await this.sendInviteeEmail(emailTemplate, userData, null, { roles: roleToString })
}
} else {
+ //delete invitation entry
isErrorOccured = true
await userInviteQueries.deleteOne(newInvitee.id)
invitee.statusOrUserId = newUserCred
@@ -360,12 +441,14 @@ module.exports = class UserInviteHelper {
}
}
+ //convert roles array to string
+ invitee.roles = invitee.roles.length > 0 ? invitee.roles.join(',') : ''
input.push(invitee)
}
+ //generate output csv
const csvContent = utils.generateCSVContent(input)
const outputFilePath = path.join(inviteeFileDir, outputFileName)
-
fs.writeFileSync(outputFilePath, csvContent)
return {
@@ -418,13 +501,16 @@ module.exports = class UserInviteHelper {
}
}
- static async sendInviteeEmail(templateData, userData, inviteeUploadURL = null) {
+ static async sendInviteeEmail(templateData, userData, inviteeUploadURL = null, subjectComposeData = {}) {
try {
const payload = {
type: common.notificationEmailType,
email: {
to: userData.email,
- subject: templateData.subject,
+ subject:
+ subjectComposeData && Object.keys(subjectComposeData).length > 0
+ ? utils.composeEmailBody(templateData.subject, subjectComposeData)
+ : templateData.subject,
body: utils.composeEmailBody(templateData.body, {
name: userData.name,
role: userData.role || '',
@@ -432,12 +518,12 @@ module.exports = class UserInviteHelper {
appName: process.env.APP_NAME,
inviteeUploadURL,
portalURL: process.env.PORTAL_URL,
+ roles: userData.roles || '',
}),
},
}
await kafkaCommunication.pushEmailToKafka(payload)
-
return {
success: true,
}