feat : customer can set User Name

feat : customer can update username.
wip : update the SMS template for user name.
This commit is contained in:
2025-10-24 13:04:58 +05:30
parent 96af9ff264
commit 08e47e2e92
6 changed files with 116 additions and 10 deletions

View File

@@ -12,11 +12,9 @@ async function login(req, res) {
const { customerNo, password, otp } = req.body;
const loginType = req.headers['x-login-type'] || 'standard';
if (!customerNo || !password) {
return res.status(400).json({ error: 'customerNo and password are required' });
}
const currentTime = new Date().toISOString();
const MAX_ATTEMPTS = 3; // Max invalid attempts before lock
const BLOCK_DURATION = 15 * 60 * 60; // 1 day
@@ -25,7 +23,6 @@ async function login(req, res) {
const blockedKey = `login:blocked:${customerNo}`;
const attemptsKey = `login:attempts:${customerNo}`;
const userCheck = await authService.findUserByCustomerNo(customerNo);
if (loginType.toUpperCase() === 'IB') {
@@ -70,7 +67,6 @@ async function login(req, res) {
}
}
// --- Step 4: If login successful, reset Redis attempts ---
await setJson(attemptsKey, 0); // reset counter
@@ -103,12 +99,10 @@ async function login(req, res) {
ibAccess: user.ib_access_level,
mbAccess: user.mb_access_level,
};
await db.query('UPDATE users SET last_login = $1 WHERE customer_no = $2', [
currentTime,
customerNo,
]);
logger.info(`Login successful | Type: ${loginType}`);
return res.json({ token, FirstTimeLogin, loginPswExpiry, rights });
} catch (err) {
@@ -117,7 +111,6 @@ async function login(req, res) {
}
}
async function fetchUserDetails(req, res) {
const customerNo = req.user;
try {
@@ -146,7 +139,6 @@ async function tpin(req, res) {
}
}
async function setTpin(req, res) {
const customerNo = req.user;
try {
@@ -259,6 +251,59 @@ async function changeTransPassword(req, res) {
}
}
async function isUserNameExits(req, res) {
try {
const customerNo = req.user;
const user = await authService.findUserByCustomerNo(customerNo);
if (!user) {
return res.status(404).json({ error: 'USER_NOT_FOUND' });
}
const userName = await authService.CheckUserName(customerNo);
return res.json({ user_name: userName });
} catch (error) {
console.error(error);
return res.status(500).json({ error: 'INTERNAL_SERVER_ERROR' });
}
}
async function setUserName(req, res) {
const customerNo = req.user;
try {
const user = await authService.findUserByCustomerNo(customerNo);
if (!user) {
return res.status(404).json({ error: 'USER_NOT_FOUND' });
}
const userNameIsExits = await authService.CheckUserName(customerNo);
const { user_name } = req.body;
if (!userNameIsExits) {
await authService.setUserName(customerNo, user_name);
logger.info('User name has been set for first time.');
return res.json({ message: 'All set! Your username has been saved.' });
}
if (userNameIsExits) {
const historyRes = await db.query('SELECT preferred_name FROM preferred_name_history WHERE customer_no = $1 ORDER BY changed_at DESC LIMIT 5',
[customerNo]
);
// maximum 5 times can changed username
const history = historyRes.rows.map((r) => r.preferred_name.toLowerCase());
if (history.length >= 5) {
return res.status(429).json({ error: "Preferred name change limit reached -5 times" });
}
// Cannot match last 2
const lastTwo = history.slice(0, 2);
if (lastTwo.includes(user_name.toLowerCase())) {
return res.status(409).json({ error: "Preferred name cannot match last 2 preferred names"});
}
await authService.setUserName(customerNo, user_name);
logger.info('User name has been updated.');
return res.json({ message: 'All set! Your username has been updated.' });
}
} catch (error) {
logger.error(error);
return res.status(500).json({ error: 'CANNOT UPDATE USER NAME' });
}
}
module.exports = {
login,
tpin,
@@ -268,4 +313,6 @@ module.exports = {
fetchUserDetails,
changeLoginPassword,
changeTransPassword,
isUserNameExits,
setUserName,
};

View File

@@ -21,6 +21,7 @@ async function SendOtp(req, res) {
ref,
date,
userOtp,
PreferName,
} = req.body;
if (!mobileNumber || !type) {
@@ -99,6 +100,13 @@ async function SendOtp(req, res) {
otp = generateOTP(6);
message = templates.EMandate(otp);
break;
case 'USERNAME_UPDATED':
otp = generateOTP(6);
message = templates.USERNAME_UPDATED(otp);
break;
case 'USERNAME_SAVED':
message = templates.USERNAME_SAVED(PreferName);
break;
default:
return res.status(400).json({ error: 'Invalid OTP type' });
}