Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,6 @@ EVENT_TENANT_LISTENER_API='http://interface:3567/scp/v1/tenant/add'
#Enable / disable organization event
EVENT_ENABLE_ORGANIZATION_EVENTS=true
#Event Kafka topic for organization create/update
EVENT_ORGANIZATION_KAFKA_TOPIC='dev.organizationEvent'
EVENT_ORGANIZATION_KAFKA_TOPIC='dev.organizationEvent'
#Service name for health Check
SERVICE_NAME = 'UserService'
4,122 changes: 3,638 additions & 484 deletions src/api-doc/MentorED-Users.postman_collection.json

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions src/configs/kafka.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ const logger = elevateLog.init()

module.exports = async () => {
const kafkaIps = process.env.KAFKA_URL.split(',')

const KafkaClient = new Kafka({
clientId: 'mentoring',
clientId: 'user-service',
brokers: kafkaIps,
})

const producer = KafkaClient.producer()
const consumer = KafkaClient.consumer({ groupId: process.env.KAFKA_GROUP_ID })

await producer.connect()
await consumer.connect()

Expand All @@ -36,7 +36,8 @@ module.exports = async () => {
})

const subscribeToConsumer = async () => {
await consumer.subscribe({ topics: [process.env.CLEAR_INTERNAL_CACHE] })
const topics = [process.env.CLEAR_INTERNAL_CACHE].filter(Boolean)
await consumer.subscribe({ topics })
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
try {
Expand All @@ -52,6 +53,7 @@ module.exports = async () => {
},
})
}

subscribeToConsumer()

global.kafkaProducer = producer
Expand Down
1 change: 1 addition & 0 deletions src/controllers/v1/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module.exports = class Account {
}

const device_info = req.headers && req.headers['device-info'] ? JSON.parse(req.headers['device-info']) : {}

try {
const createdAccount = await accountService.create(params, device_info, domain)
return createdAccount
Expand Down
5 changes: 5 additions & 0 deletions src/envVariables.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,11 @@ let enviromentVariables = {
optional: true,
default: 'x-tenant-code',
},
SERVICE_NAME: {
message: 'Required SERVICE_NAME',
optional: true,
default: 'UserService',
},
}
let success = true

Expand Down
10 changes: 7 additions & 3 deletions src/health-checks/health-check.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@
const { healthCheckHandler } = require('elevate-services-health-check')
const healthCheckConfig = require('./health.config')
const { v1: uuidv1 } = require('uuid')
const packageFile = require('../package.json')

let health_check = async function (req, res) {
try {
const response = await healthCheckHandler(healthCheckConfig, req.query.basicCheck, req.query.serviceName)
const response = await healthCheckHandler(
healthCheckConfig,
req.query.basicCheck,
req.query.serviceName,
packageFile.version
)
res.status(200).json(response)
} catch (err) {
console.error('Health config validation failed:', err.message || err)
res.status(400).json({
id: 'userService.Health.API',
ver: '1.0',
ts: new Date(),
params: {
resmsgid: uuidv1(),
Expand All @@ -41,7 +46,6 @@ let healthCheckStatus = function (req, res) {
let response = function (req, result) {
return {
id: 'User.service.Health.API',
ver: '1.0',
ts: new Date(),
params: {
resmsgid: uuidv1(),
Expand Down
1 change: 0 additions & 1 deletion src/health-checks/health.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

module.exports = {
name: process.env.SERVICE_NAME,
version: '1.0.0',
checks: {
kafka: {
enabled: true,
Expand Down
16 changes: 6 additions & 10 deletions src/helpers/eventBroadcasterMain.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ const isEventEnabled = (eventGroup) => {
case 'organizationEvents':
return process.env.EVENT_ENABLE_ORG_EVENTS !== 'false'
case 'userEvents':
return process.env.EVENT_ENABLE_USER_EVENTS !== 'false'
const apiEnabled = process.env.EVENT_ENABLE_USER_EVENTS !== 'false'
return apiEnabled
case 'tenantEvents':
return process.env.EVENT_ENABLE_TENANT_EVENTS !== 'false'
case 'userEvents-kafka':
return process.env.EVENT_ENABLE_USER_KAFKA_EVENTS !== 'false'
const kafkaEnabled = process.env.EVENT_ENABLE_USER_KAFKA_EVENTS !== 'false'
return kafkaEnabled
case 'tenantEvents-kafka':
return process.env.EVENT_ENABLE_TENANT_KAFKA_EVENTS !== 'false'
case 'organizationEvents-kafka':
Expand All @@ -43,7 +45,6 @@ const isEventEnabled = (eventGroup) => {

exports.eventBroadcasterMain = async (eventGroup, { requestBody, headers = {}, isInternal = true }) => {
try {
console.log('API Event ')
if (!requestBody) throw new Error('Event Body Generation Failed')
if (!isEventEnabled(eventGroup)) throw new Error(`Events Not Enabled For The Group "${eventGroup}"`)
if (isInternal) headers.internal_access_token = process.env.INTERNAL_ACCESS_TOKEN
Expand All @@ -52,13 +53,12 @@ exports.eventBroadcasterMain = async (eventGroup, { requestBody, headers = {}, i
return requester.post(endPoint, '', headers, requestBody)
})
const results = await Promise.allSettled(requestPromises)
console.log('PROMISE ------->>> ', results)
results.forEach((result, index) => {
if (result.status === 'rejected')
console.error(`Error for endpoint ${endPoints[index].url}:`, result.reason)
})
} catch (err) {
console.log(err)
console.log(`[EVENT BROADCASTER] API Event error: ${err}`)
}
}
exports.eventBroadcasterKafka = async (eventGroup, { requestBody }) => {
Expand All @@ -78,18 +78,14 @@ exports.eventBroadcasterKafka = async (eventGroup, { requestBody }) => {
await kafkaCommunication.pushTenantEventsToKafka(requestBody)
break
default:
console.log('No Kafka Event Group Found')
break
}
} catch (err) {
console.log(err)
console.log(`[EVENT BROADCASTER] Kafka Event error: ${err}`)
}
}
exports.broadcastEvent = async (eventGroup, { requestBody, headers = {}, isInternal = true }) => {
try {
//TODO: Remove this log after testing
console.log(util.inspect(requestBody, { depth: null, colors: true, compact: false }))

// Fire both broadcaster functions concurrently
const broadcastPromises = [
exports.eventBroadcasterMain(eventGroup, { requestBody, headers, isInternal }),
Expand Down
4 changes: 2 additions & 2 deletions src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.shikshalokam.mentoring.userservice",
"version": "1.0.0",
"version": "3.3.24",
"description": "A user service for mentoring capability",
"main": "app.js",
"bin": {
Expand Down Expand Up @@ -45,7 +45,7 @@
"elevate-encryption": "^1.0.1",
"elevate-logger": "^3.1.0",
"elevate-node-cache": "^1.0.6",
"elevate-services-health-check": "^0.0.6",
"elevate-services-health-check": "^0.0.9",
"email-validator": "^2.0.4",
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
Expand Down
35 changes: 16 additions & 19 deletions src/services/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ module.exports = class AccountHelper {
})

const tenantDomain = await tenantDomainQueries.findOne({ domain })

if (!tenantDomain) {
return notFoundResponse('TENANT_DOMAIN_NOT_FOUND_PING_ADMIN')
}
Expand All @@ -75,6 +76,7 @@ module.exports = class AccountHelper {
code: tenantDomain.tenant_code,
status: common.ACTIVE_STATUS,
})

if (!tenantDetail) {
return notFoundResponse('TENANT_NOT_FOUND_PING_ADMIN')
}
Expand Down Expand Up @@ -109,18 +111,26 @@ module.exports = class AccountHelper {
let plaintextEmailId = null
if (bodyData.email) {
plaintextEmailId = bodyData.email.toLowerCase()
encryptedEmailId = emailEncryption.encrypt(plaintextEmailId)
bodyData.email = encryptedEmailId
try {
encryptedEmailId = emailEncryption.encrypt(plaintextEmailId)
bodyData.email = encryptedEmailId
} catch (encryptError) {
throw encryptError
}
}

// Handle phone encryption if provided
let encryptedPhoneNumber = null
let plaintextPhoneNumber = null
if (bodyData.phone && bodyData.phone_code) {
plaintextPhoneNumber = bodyData.phone
encryptedPhoneNumber = emailEncryption.encrypt(plaintextPhoneNumber)
bodyData.phone = encryptedPhoneNumber
bodyData.phone_code = bodyData.phone_code // Store phone_code separately
try {
encryptedPhoneNumber = emailEncryption.encrypt(plaintextPhoneNumber)
bodyData.phone = encryptedPhoneNumber
bodyData.phone_code = bodyData.phone_code // Store phone_code separately
} catch (encryptError) {
throw encryptError
}
}

const criteria = []
Expand Down Expand Up @@ -630,7 +640,6 @@ module.exports = class AccountHelper {
result,
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -827,7 +836,6 @@ module.exports = class AccountHelper {
result,
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -870,7 +878,6 @@ module.exports = class AccountHelper {
message: 'LOGGED_OUT_SUCCESSFULLY',
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -1105,7 +1112,6 @@ module.exports = class AccountHelper {
message: 'OTP_SENT_SUCCESSFULLY',
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -1525,7 +1531,6 @@ module.exports = class AccountHelper {
result,
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -1677,7 +1682,6 @@ module.exports = class AccountHelper {
})
}
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -1708,9 +1712,7 @@ module.exports = class AccountHelper {

// Clear Redis cache asynchronously (fire and forget)
const redisUserKey = `${common.redisUserPrefix}${tenantCode}_${userId}`
utilsHelper.redisDel(redisUserKey).catch((err) => {
console.error('Redis delete error:', err)
})
utilsHelper.redisDel(redisUserKey).catch((err) => {})

return responses.successResponse({
statusCode: httpStatusCode.ok,
Expand Down Expand Up @@ -1829,7 +1831,6 @@ module.exports = class AccountHelper {
message: 'USER_ROLE_UPDATED_SUCCESSFULLY',
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -1933,7 +1934,6 @@ module.exports = class AccountHelper {
},
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -2032,7 +2032,6 @@ module.exports = class AccountHelper {
result,
})
} catch (error) {
console.log(error)
throw error
}
}
Expand Down Expand Up @@ -2070,7 +2069,6 @@ module.exports = class AccountHelper {
user.email = emailEncryption.decrypt(user.email)
userIdsAndInvalidEmails.push(user.id)
} catch (err) {
console.error(`Decryption failed for email: ${encryptedEmail}`, err)
const originalEmail = emailEncryption.decrypt(encryptedEmail)
userIdsAndInvalidEmails.push(originalEmail)
}
Expand All @@ -2079,7 +2077,6 @@ module.exports = class AccountHelper {
const originalEmail = emailEncryption.decrypt(encryptedEmail)
userIdsAndInvalidEmails.push(originalEmail)
} catch (err) {
console.error(`Decryption failed for email: ${encryptedEmail}`, err)
userIdsAndInvalidEmails.push('Decryption failed')
}
}
Expand Down
15 changes: 5 additions & 10 deletions src/services/tenant.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const organizationFeatureQueries = require('@database/queries/organization-featu
const utils = require('@generics/utils')
const _ = require('lodash')
const responses = require('@helpers/responses')
const { Op } = require('sequelize')
const { Op, UniqueConstraintError } = require('sequelize')
const { broadcastEvent } = require('@helpers/eventBroadcasterMain')
const TenantDTO = require('@dtos/tenantDTO')

Expand Down Expand Up @@ -59,20 +59,14 @@ module.exports = class tenantHelper {
try {
tenantCreateResponse = await tenantQueries.create(tenantCreateBody)
} catch (error) {
// Check for unique constraint violation (duplicate code)
if (
error.code === '23505' ||
error.message.includes('unique constraint') ||
error.message.includes('duplicate key')
) {
if (error instanceof UniqueConstraintError) {
return responses.failureResponse({
statusCode: httpStatusCode.bad_request,
message: 'TENANT_ALREADY_EXISTS',
result: {},
})
}
console.log(error)
throw error // Re-throw other errors
throw error
}

// push function to rollback tenant creation into stack
Expand Down Expand Up @@ -362,7 +356,8 @@ module.exports = class tenantHelper {
visibility: userRole.visibility,
tenant_code: tenantCreateResponse.code,
},
defaultOrgId
defaultOrgId,
tenantCreateResponse.code
)
})

Expand Down