Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1171- STORY ]- User Session Implementation added. #473

Merged
merged 11 commits into from
Apr 1, 2024
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:16
FROM node:20

#Set working directory
WORKDIR /var/src/
Expand Down
8 changes: 7 additions & 1 deletion src/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,11 @@ DOWNLOAD_URL_EXPIRATION_DURATION = 120000
#database url
DATABASE_URL=postgres://postgres:postgres@localhost:5432/elevate-user

#allowed idle time
ALLOWED_IDLE_TIME=300000

# Expiry time for the signed urls
SIGNED_URL_EXPIRY_IN_MILLISECONDS = 120000
SIGNED_URL_EXPIRY_IN_MILLISECONDS = 120000

# Allowed active sessions
ALLOWED_ACTIVE_SESSIONS = 5
2 changes: 2 additions & 0 deletions src/constants/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module.exports = {
'/user/v1/account/search',
'/user/v1/organization/list',
'/user/v1/user-role/default',
'/user/v1/account/validateUserSession',
],
notificationEmailType: 'email',
accessTokenExpiry: process.env.ACCESS_TOKEN_EXPIRY,
Expand Down Expand Up @@ -59,6 +60,7 @@ module.exports = {
roleAssociationName: 'user_roles',
ACTIVE_STATUS: 'ACTIVE',
INACTIVE_STATUS: 'INACTIVE',
EXPIRED_STATUS: 'EXPIRED',
MENTOR_ROLE: 'mentor',
MENTEE_ROLE: 'mentee',
SESSION_MANAGER_ROLE: 'session_manager',
Expand Down
52 changes: 47 additions & 5 deletions src/controllers/v1/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

// Dependencies
const accountService = require('@services/account')

const userSessionsService = require('@services/user-sessions')
module.exports = class Account {
/**
* create mentee account
Expand All @@ -24,8 +24,9 @@ module.exports = class Account {

async create(req) {
const params = req.body
const device_info = req.headers && req.headers['device-info'] ? JSON.parse(req.headers['device-info']) : {}
try {
const createdAccount = await accountService.create(params)
const createdAccount = await accountService.create(params, device_info)
return createdAccount
} catch (error) {
return error
Expand All @@ -45,8 +46,9 @@ module.exports = class Account {

async login(req) {
const params = req.body
const device_info = req.headers && req.headers['device-info'] ? JSON.parse(req.headers['device-info']) : {}
try {
const loggedInAccount = await accountService.login(params)
const loggedInAccount = await accountService.login(params, device_info)
return loggedInAccount
} catch (error) {
return error
Expand All @@ -69,7 +71,8 @@ module.exports = class Account {
const loggedOutAccount = await accountService.logout(
req.body,
req.decodedToken.id,
req.decodedToken.organization_id
req.decodedToken.organization_id,
req.decodedToken.session_id
)
return loggedOutAccount
} catch (error) {
Expand Down Expand Up @@ -128,7 +131,8 @@ module.exports = class Account {
async resetPassword(req) {
const params = req.body
try {
const result = await accountService.resetPassword(params)
const deviceInfo = req.headers && req.headers['device-info'] ? JSON.parse(req.headers['device-info']) : {}
const result = await accountService.resetPassword(params, deviceInfo)
return result
} catch (error) {
return error
Expand Down Expand Up @@ -266,4 +270,42 @@ module.exports = class Account {
return error
}
}

/**
* Retrieve user sessions based on the request parameters.
* @param {Object} req - The request object containing query parameters and decoded token.
* @returns {Promise<Object>} - A promise that resolves to the user session details.
*/

async sessions(req) {
try {
const filter = req.query && req.query.status ? req.query.status.toUpperCase() : ''
const userSessionDetails = await userSessionsService.list(
req.decodedToken.id,
filter,
req.pageSize,
req.pageNo
)
return userSessionDetails
} catch (error) {
return error
}
}

/**
* Validate a user session based on the provided token.
* @param {Object} req - The request object containing the token in the request body.
* @param {string} req.body.token - The token to validate the user session.
* @returns {Promise<Object>} - A promise that resolves to the validation result of the user session.
*/

async validateUserSession(req) {
try {
const token = req.body.token
const validateUserSession = await userSessionsService.validateUserSession(token)
return validateUserSession
} catch (error) {
return error
}
}
}
3 changes: 2 additions & 1 deletion src/controllers/v1/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ module.exports = class Admin {

async login(req) {
try {
const loggedInAccount = await adminService.login(req.body)
const device_info = req.headers && req.headers['device-info'] ? req.headers['device-info'] : {}
const loggedInAccount = await adminService.login(req.body, device_info)
return loggedInAccount
} catch (error) {
return error
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict'

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('user_sessions', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
user_id: {
type: Sequelize.INTEGER,
allowNull: false,
},
started_at: {
type: Sequelize.BIGINT,
allowNull: false,
},
ended_at: {
type: Sequelize.BIGINT,
allowNull: true,
},
token: {
type: Sequelize.TEXT,
allowNull: true,
},
device_info: {
type: Sequelize.JSONB,
allowNull: true,
},
refresh_token: {
type: Sequelize.TEXT,
allowNull: true,
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
deleted_at: {
type: Sequelize.DATE,
},
})
},

async down(queryInterface, Sequelize) {
await queryInterface.dropTable('user_sessions')
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict'

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
try {
const permissionsData = [
{
code: 'get_user_sessions',
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
status: 'ACTIVE',
},
{
code: 'validate_user_sessions',
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
status: 'ACTIVE',
},
]

// Batch insert permissions
await queryInterface.bulkInsert(
'permissions',
permissionsData.map((permission) => ({
...permission,
created_at: new Date(),
updated_at: new Date(),
}))
)
} catch (error) {
console.error('Error in migration:', error)
throw error
}
},

async down(queryInterface, Sequelize) {
try {
// Rollback migration by deleting all permissions
await queryInterface.bulkDelete('permissions', null, {})
} catch (error) {
console.error('Error in rollback migration:', error)
throw error
}
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
'use strict'

require('module-alias/register')
require('dotenv').config()
const common = require('@constants/common')
const Permissions = require('@database/models/index').Permission

const getPermissionId = async (module, request_type, api_path) => {
try {
const permission = await Permissions.findOne({
where: { module, request_type, api_path },
})
if (!permission) {
throw new Error(
`Permission not found for module: ${module}, request_type: ${request_type}, api_path: ${api_path}`
)
}
return permission.id
} catch (error) {
throw new Error(`Error while fetching permission: ${error.message}`)
}
}

module.exports = {
up: async (queryInterface, Sequelize) => {
try {
const rolePermissionsData = await Promise.all([
{
role_title: common.MENTOR_ROLE,
permission_id: await getPermissionId('account', ['GET'], '/user/v1/account/sessions'),
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
},
{
role_title: common.ORG_ADMIN_ROLE,
permission_id: await getPermissionId('account', ['GET'], '/user/v1/account/sessions'),
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
},
{
role_title: common.USER_ROLE,
permission_id: await getPermissionId('account', ['GET'], '/user/v1/account/sessions'),
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
},
{
role_title: common.ADMIN_ROLE,
permission_id: await getPermissionId('account', ['GET'], '/user/v1/account/sessions'),
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
},
{
role_title: common.SESSION_MANAGER_ROLE,
permission_id: await getPermissionId('account', ['GET'], '/user/v1/account/sessions'),
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
},
{
role_title: common.MENTEE_ROLE,
permission_id: await getPermissionId('account', ['GET'], '/user/v1/account/sessions'),
module: 'account',
request_type: ['GET'],
api_path: '/user/v1/account/sessions',
},

{
role_title: common.MENTOR_ROLE,
permission_id: await getPermissionId('account', ['POST'], '/user/v1/account/validateUserSession'),
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
},
{
role_title: common.MENTEE_ROLE,
permission_id: await getPermissionId('account', ['POST'], '/user/v1/account/validateUserSession'),
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
},
{
role_title: common.ORG_ADMIN_ROLE,
permission_id: await getPermissionId('account', ['POST'], '/user/v1/account/validateUserSession'),
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
},
{
role_title: common.USER_ROLE,
permission_id: await getPermissionId('account', ['POST'], '/user/v1/account/validateUserSession'),
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
},
{
role_title: common.ADMIN_ROLE,
permission_id: await getPermissionId('account', ['POST'], '/user/v1/account/validateUserSession'),
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
},
{
role_title: common.SESSION_MANAGER_ROLE,
permission_id: await getPermissionId('account', ['POST'], '/user/v1/account/validateUserSession'),
module: 'account',
request_type: ['POST'],
api_path: '/user/v1/account/validateUserSession',
},
])

await queryInterface.bulkInsert(
'role_permission_mapping',
rolePermissionsData.map((data) => ({
...data,
created_at: new Date(),
updated_at: new Date(),
created_by: 0,
}))
)
} catch (error) {
console.log(error)
console.error(`Migration error: ${error.message}`)
throw error
}
},

down: async (queryInterface, Sequelize) => {
try {
await queryInterface.bulkDelete('role_permission_mapping', null, {})
} catch (error) {
console.error(`Rollback migration error: ${error.message}`)
throw error
}
},
}
Loading