2026-06-14 12:46:29 +06:00
using Ease.NetCore.DataAccess ;
using Ease.NetCore.DataAccess.SQL ;
using Ease.NetCore.Utility ;
2026-07-06 17:23:05 +06:00
using Microsoft.Data.SqlClient ;
using Microsoft.Extensions.Options ;
2026-06-14 12:46:29 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models ;
using OnlineSalesAutoCrop.CoreAPI.Models.Global ;
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems ;
2026-07-06 17:23:05 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations ;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp ;
2026-06-14 12:46:29 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems ;
2026-07-06 17:23:05 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp ;
2026-06-14 12:46:29 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems ;
2026-07-06 17:23:05 +06:00
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Auth ;
2026-06-14 12:46:29 +06:00
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Systems
{
2026-07-06 17:23:05 +06:00
public class UserService ( IOptions < AppSettings > settings , IOptions < MenuSettings > menuSettings , IRefreshTokenService refreshTokenService ) : IUserService
2026-06-15 18:26:58 +06:00
{
private readonly AppSettings _settings = settings ? . Value ;
private readonly MenuSettings _menuSettings = menuSettings ? . Value ;
2026-07-06 17:23:05 +06:00
private readonly IRefreshTokenService _refreshTokenService = refreshTokenService ;
2026-06-15 18:26:58 +06:00
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="ipAddress"></param>
/// <param name="checkPwd"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < User > LoginAsync ( LoginRequest request , string ipAddress , bool checkPwd )
{
User user = new ( ) { LoginId = request . LoginId , LoginStatus = EnumLoginStatus . Unsuccessful } ;
2026-08-06 16:57:29 +06:00
try
{
string password = EncryptPassword ( password : request . Password ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
bool batchEnabled = false ;
DateTime sysDate = DateTime . Today . Date ;
string appVer = string . Empty , alParams = string . Empty ;
int maxTryCount = 5 , lockTime = 1 , marMonths = 24 , idleTime = 0 , timeoutTime = 0 , pingTime = 0 , bmProcessId = 0 , prProcessId = 0 ;
#region Read Params from ThisSystem
using ( IDataReader dr = tc . ExecuteReader ( "SELECT MaxTryCount, LockTime, MarMonths, CAST(GETDATE() as date), AppVersion, AutoLogoutParams, BatchEnabled, BmProcessId, PrProcessId FROM ThisSystem" ) )
{
if ( dr . Read ( ) )
{
maxTryCount = dr . GetInt16 ( 0 ) ;
lockTime = dr . GetInt16 ( 1 ) ;
marMonths = dr . GetInt16 ( 2 ) ;
sysDate = dr . GetDateTime ( 3 ) ;
appVer = dr . GetString ( 4 ) ;
alParams = dr . IsDBNull ( 5 ) ? string . Empty : dr . GetString ( 5 ) ;
batchEnabled = ! dr . IsDBNull ( 6 ) & & dr . GetInt16 ( 6 ) ! = 0 ;
bmProcessId = dr . IsDBNull ( 7 ) ? 0 : dr . GetInt16 ( 7 ) ;
prProcessId = dr . IsDBNull ( 8 ) ? 0 : dr . GetInt16 ( 8 ) ;
}
dr . Close ( ) ;
}
if ( ! string . IsNullOrEmpty ( alParams ) )
{
string [ ] times = alParams . Split ( separator : ',' , options : StringSplitOptions . RemoveEmptyEntries ) ;
if ( times . Length = = 3 )
{
if ( ! int . TryParse ( times [ 0 ] , out idleTime ) )
idleTime = 0 ;
if ( ! int . TryParse ( times [ 1 ] , out timeoutTime ) )
timeoutTime = 0 ;
if ( ! int . TryParse ( times [ 2 ] , out pingTime ) )
pingTime = 0 ;
}
}
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & ! request . AppVersion . Equals ( appVer ) )
{
user . UnsuccessfulMsg = appVer ;
user . LoginStatus = EnumLoginStatus . VersionMismatch ;
}
#endregion
2026-08-09 18:20:12 +06:00
if ( user . LoginStatus ! = EnumLoginStatus . VersionMismatch )
{
#region Read User data using authentication data
string commandText = SQLParser . MakeSQL ( "SELECT UserId,LoginId, UserName, Status,AccessStatus,NeverExpires, MobileNo, EmailAddress, "
+ " IsLocked, UserPlatformId, UserRoleType, EmployeeNumber FROM Users"
+ " WHERE (LoginID=%s OR MobileNo=%s OR EmailAddress=%s) AND Password=%s" , request . LoginId , request . LoginId , request . LoginId , password ) ;
using ( IDataReader dr = tc . ExecuteReader ( commandText : commandText ) )
{
if ( dr . Read ( ) )
{
user = new User
{
UserId = dr . GetInt32 ( 0 ) ,
LoginId = dr . GetString ( 1 ) ,
UserName = dr . GetString ( 2 ) ,
Status = ( EnumStatus ) dr . GetInt32 ( 3 ) ,
AccessStatus = ( EnumAccessStatus ) dr . GetInt32 ( 4 ) ,
NeverExpires = dr . GetBoolean ( 5 ) ,
MobileNo = dr . IsDBNull ( 6 ) ? null : dr . GetString ( 6 ) ,
EmailAddress = dr . IsDBNull ( 7 ) ? null : dr . GetString ( 7 ) ,
IsLocked = dr . GetBoolean ( 8 ) ,
UserPlatFormType = dr . IsDBNull ( 9 ) ? null : ( UserPlatFormType ) dr . GetInt32 ( 9 ) ,
UserRoleType = dr . IsDBNull ( 10 ) ? null : ( UserRoleTypeEnum ) dr . GetInt32 ( 10 ) ,
EmployeeNumber = dr . IsDBNull ( 11 ) ? null : dr . GetString ( 11 ) ,
LoginStatus = EnumLoginStatus . Success
} ;
}
dr . Close ( ) ;
}
#endregion
#region If the user was locked , try set set unlock if Time expired
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & user . IsLocked )
{
int isSuccessful = 0 ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : request . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateOutParam ( pName : "@IsSuccessful" , pType : SqlDbType . Int , pValue : isSuccessful ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.DoUnlockUser" , parameterValues : p ) ;
if ( p [ 2 ] ! = null & & p [ 2 ] . Value ! = null & & p [ 2 ] . Value ! = DBNull . Value )
isSuccessful = Convert . ToInt32 ( p [ 2 ] . Value ) ;
if ( isSuccessful = = 1 )
user . IsLocked = false ;
}
#endregion
#region Keep log for unauthrise access and Set user lock if exceeds max try
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & maxTryCount > 0 & & user . LoginStatus = = EnumLoginStatus . Unsuccessful )
{
int remainsTry = 0 ;
DateTime ? nextLoginTime = null ;
string tryLoginInfo = $"{request.LoginId}~{password}~13" ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : request . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@TryLoginInfo" , pType : SqlDbType . VarChar , pValue : tryLoginInfo , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MaxTryCount" , pType : SqlDbType . SmallInt , pValue : maxTryCount ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateOutParam ( pName : "@RemainingTry" , pType : SqlDbType . SmallInt , pValue : remainsTry ) ,
SqlHelperExtension . CreateOutParam ( pName : "@NextLoginTime" , pType : SqlDbType . DateTime , pValue : nextLoginTime ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.LogUnauthorizeAccess" , parameterValues : p ) ;
if ( p [ 5 ] ! = null & & p [ 5 ] . Value ! = null & & p [ 5 ] . Value ! = DBNull . Value )
remainsTry = Convert . ToInt32 ( p [ 5 ] . Value ) ;
if ( p [ 6 ] ! = null & & p [ 6 ] . Value ! = null & & p [ 6 ] . Value ! = DBNull . Value )
nextLoginTime = Convert . ToDateTime ( p [ 6 ] . Value ) ;
if ( remainsTry < = 0 )
{
user . IsLocked = true ;
if ( lockTime < = 0 )
{
user . NextLoginTime = nextLoginTime ;
user . UnsuccessfulMsg = "Please contact with Head office to Unlock" ;
}
else
{
user . NextLoginTime = nextLoginTime ;
user . UnsuccessfulMsg = $"You can Login after {user.NextLoginTime:dd-MMM-yyyy H:mm:ss}" ;
}
}
else
{
user . UnsuccessfulMsg = $"{remainsTry} More attempt{(remainsTry > 1 ? " s " : " ")} remaining" ;
}
}
#endregion
#region If login successful and user is active read module id for this user
if ( user . LoginStatus = = EnumLoginStatus . Success & & user . Status = = EnumStatus . Authorized & & ! user . IsLocked )
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginTime" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@LogoutTime" , pType : SqlDbType . DateTime , pValue : null )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.SaveAccessLog" , parameterValues : p ) ;
}
#endregion
#region If login successful and user is active read module id for this user
if ( user . LoginStatus = = EnumLoginStatus . Success & & user . Status = = EnumStatus . Authorized & & ! user . IsLocked )
{
int logId = 0 ;
DateTime ? logoutTime = null ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AppId" , pType : SqlDbType . VarChar , pValue : request . AppId , size : 250 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateInParam ( pName : "@AttendanceLogin" , pType : SqlDbType . Int , pValue : request . AttendanceLogin ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LocalIp" , pType : SqlDbType . VarChar , pValue : request . IpAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MacAddress" , pType : SqlDbType . VarChar , pValue : request . MacAddress , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@HostName" , pType : SqlDbType . VarChar , pValue : request . HostName , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginRemarks" , pType : SqlDbType . VarChar , pValue : request . LoginRemarks , size : 50 )
] ;
using ( IDataReader dr = tc . ExecuteReaderSp ( spName : "dbo.GetPermissionKeys" , parameterValues : p ) )
{
user . ModuleIds = [ ] ;
while ( dr . Read ( ) )
{
string moduleId = dr . GetString ( 0 ) ;
user . ModuleIds . Add ( moduleId ) ;
logId = dr . GetInt32 ( 1 ) ;
if ( dr . GetInt16 ( 2 ) ! = 0 ) //Alow add
{
user . ModuleIds . Add ( $"{moduleId}_1" ) ;
}
if ( dr . GetInt16 ( 3 ) ! = 0 ) //Alow edit
{
user . ModuleIds . Add ( $"{moduleId}_2" ) ;
}
if ( dr . GetInt16 ( 4 ) ! = 0 ) //Allow Delete
{
user . ModuleIds . Add ( $"{moduleId}_3" ) ;
}
logoutTime = dr . IsDBNull ( 5 ) ? null : dr . GetDateTime ( 5 ) ;
}
dr . Close ( ) ;
}
user . LogoutTime = logoutTime ;
//Read User TeamSpace Ids
using ( IDataReader dr = tc . ExecuteReader ( "SELECT TeamSpaceId FROM TeamSpaceUsers WHERE UserId=%n" , user . UserId ) )
{
while ( dr . Read ( ) )
{
user . TeamSpaceIds . Add ( dr . GetInt32 ( 0 ) ) ;
}
dr . Close ( ) ;
}
//Pending Notification count
//user.NotificationCount = GetPendingNotifCount(tc: tc, userId: user.Id);
}
#endregion
}
2026-08-06 16:57:29 +06:00
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
2026-06-15 18:26:58 +06:00
return user ;
}
2026-07-06 17:23:05 +06:00
public async Task < AppAuthUserResponse > LoginAsync ( MobileAppAuthRequest request , string ipAddress )
{
AppAuthUserResponse response = null ;
try
{
string password = EncryptPassword ( password : request . Password ) ;
User user = null ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
DateTime sysDate = DateTime . Today . Date ;
string appVer = string . Empty , alParams = string . Empty ;
int maxTryCount = 5 , lockTime = 1 ;
bool initialPassword = false ;
#region Read User data using authentication data
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . NVarChar , pValue : request . LoginId )
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetUserByLogin" , parameterValues : p ) )
{
if ( dr . Read ( ) )
{
user = new User ( ) ;
{
user . UserId = dr . GetInt32 ( 0 ) ;
user . Password = dr . GetString ( 1 ) ;
user . LoginId = dr . GetString ( 2 ) ;
user . UserName = dr . GetString ( 3 ) ;
user . Status = ( EnumStatus ) dr . GetInt32 ( 4 ) ;
user . MobileNo = dr . GetString ( 5 ) ;
user . EmailAddress = dr . GetString ( 6 ) ;
user . AuthKey = dr . GetString ( 7 ) ;
user . AuthValue = dr . GetString ( 8 ) ;
user . IsLocked = dr . GetBoolean ( 9 ) ;
user . LoginStatus = EnumLoginStatus . Success ;
user . UserRoleType = ( UserRoleTypeEnum ) dr . GetInt32 ( 10 ) ;
user . EmployeeNumber = dr . GetString ( 11 ) ;
user . DesignationCode = dr . GetString ( 12 ) ;
user . DesignationName = dr . GetString ( 13 ) ;
} ;
initialPassword = dr . GetInt32 ( 14 ) > 0 ;
}
dr . Close ( ) ;
}
if ( user is null )
{
tc . End ( ) ;
2026-07-08 14:51:20 +06:00
response = new ( ) ;
2026-07-27 18:16:10 +06:00
response . IsAuthorized = false ;
2026-07-07 18:14:18 +06:00
return response ;
2026-07-06 17:23:05 +06:00
}
if ( ! password . Equals ( user . Password ) )
{
tc . End ( ) ;
2026-07-08 14:51:20 +06:00
response = new ( ) ;
2026-07-07 18:14:18 +06:00
response . IsAuthorized = false ;
response . LoginStatus = EnumLoginStatus . Unsuccessful ;
return response ;
2026-07-06 17:23:05 +06:00
}
#endregion
#region If the user was locked , try set set unlock if Time expired
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & user . IsLocked )
{
int isSuccessful = 0 ;
p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : request . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateOutParam ( pName : "@IsSuccessful" , pType : SqlDbType . Int , pValue : isSuccessful ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.DoUnlockUser" , parameterValues : p ) ;
if ( p [ 2 ] ! = null & & p [ 2 ] . Value ! = null & & p [ 2 ] . Value ! = DBNull . Value )
isSuccessful = Convert . ToInt32 ( p [ 2 ] . Value ) ;
if ( isSuccessful = = 1 )
user . IsLocked = false ;
}
#endregion
#region Keep log for unauthrise access and Set user lock if exceeds max try
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & maxTryCount > 0 & & user . LoginStatus = = EnumLoginStatus . Unsuccessful )
{
int remainsTry = 0 ;
DateTime ? nextLoginTime = null ;
string tryLoginInfo = $"{request.LoginId}~{password}~13" ;
p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : request . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@TryLoginInfo" , pType : SqlDbType . VarChar , pValue : tryLoginInfo , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MaxTryCount" , pType : SqlDbType . SmallInt , pValue : maxTryCount ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateOutParam ( pName : "@RemainingTry" , pType : SqlDbType . SmallInt , pValue : remainsTry ) ,
SqlHelperExtension . CreateOutParam ( pName : "@NextLoginTime" , pType : SqlDbType . DateTime , pValue : nextLoginTime ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.LogUnauthorizeAccess" , parameterValues : p ) ;
if ( p [ 5 ] ! = null & & p [ 5 ] . Value ! = null & & p [ 5 ] . Value ! = DBNull . Value )
remainsTry = Convert . ToInt32 ( p [ 5 ] . Value ) ;
if ( p [ 6 ] ! = null & & p [ 6 ] . Value ! = null & & p [ 6 ] . Value ! = DBNull . Value )
nextLoginTime = Convert . ToDateTime ( p [ 6 ] . Value ) ;
if ( remainsTry < = 0 )
{
user . IsLocked = true ;
if ( lockTime < = 0 )
{
user . NextLoginTime = nextLoginTime ;
user . UnsuccessfulMsg = "Please contact with Head office to Unlock" ;
}
else
{
user . NextLoginTime = nextLoginTime ;
user . UnsuccessfulMsg = $"You can Login after {user.NextLoginTime:dd-MMM-yyyy H:mm:ss}" ;
}
}
else
{
user . UnsuccessfulMsg = $"{remainsTry} More attempt{(remainsTry > 1 ? " s " : " ")} remaining" ;
}
}
#endregion
#region If login successful and user is active read module id for this user
if ( user . LoginStatus = = EnumLoginStatus . Success & & user . Status = = EnumStatus . Authorized & & ! user . IsLocked )
{
p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginTime" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@LogoutTime" , pType : SqlDbType . DateTime , pValue : null )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.SaveAccessLog" , parameterValues : p ) ;
}
#endregion
response = new ( )
{
UserId = user . UserId ,
Name = user . UserName ,
LoginId = user . LoginId ,
Email = user . EmailAddress ,
MobileNumber = user . MobileNo ,
IsLocked = user . IsLocked ,
UserRole = user . UserRoleType . Value ,
LoginStatus = user . LoginStatus ,
IsAuthorized = EnumStatus . Authorized = = user . Status ,
EmployeeNumber = user . EmployeeNumber ,
DesignationCode = user . DesignationCode ,
DesignationName = user . DesignationName ,
IsInitialPassword = initialPassword
} ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
2026-06-16 11:36:11 +06:00
public async Task < User > IntegrationLoginAsync ( IntegrationLoginRequest request , string ipAddress , bool checkPwd )
2026-06-15 18:26:58 +06:00
{
User user = null ;
try
{
string password = EncryptPassword ( password : request . Password ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
DateTime sysDate = DateTime . Today . Date ;
string appVer = string . Empty , alParams = string . Empty ;
2026-06-16 11:36:11 +06:00
int maxTryCount = 5 , lockTime = 1 ;
2026-06-15 18:26:58 +06:00
#region Read User data using authentication data
2026-06-16 15:18:22 +06:00
string commandText = SQLParser . MakeSQL ( "SELECT UserId,Password,LoginId, UserName, Status, ISNULL(MobileNo,'')MobileNo ,ISNULL( EmailAddress,'')EmailAddress,"
2026-07-06 17:23:05 +06:00
+ " ISNULL(AuthKey,'') AuthKey, ISNULL(AuthValue,'')AuthValue, IsLocked FROM Users WHERE LoginID=%s and UserPlatformId=1 " , request . LoginId ) ;
2026-06-15 18:26:58 +06:00
using ( IDataReader dr = tc . ExecuteReader ( commandText : commandText ) )
{
if ( dr . Read ( ) )
{
user = new User
{
UserId = dr . GetInt32 ( 0 ) ,
Password = dr . GetString ( 1 ) ,
LoginId = dr . GetString ( 2 ) ,
UserName = dr . GetString ( 3 ) ,
Status = ( EnumStatus ) dr . GetInt32 ( 4 ) ,
MobileNo = dr . GetString ( 5 ) ,
EmailAddress = dr . GetString ( 6 ) ,
AuthKey = dr . GetString ( 7 ) ,
AuthValue = dr . GetString ( 8 ) ,
IsLocked = dr . GetBoolean ( 9 ) ,
LoginStatus = EnumLoginStatus . Success
} ;
}
dr . Close ( ) ;
}
if ( user is null )
{
tc . End ( ) ;
throw new InvalidOperationException ( $"User not found with login: {request.LoginId}" ) ;
}
2026-06-16 15:18:22 +06:00
if ( ! password . Equals ( user . Password ) )
2026-06-15 18:26:58 +06:00
{
tc . End ( ) ;
throw new InvalidOperationException ( $"Password mismatch for login: {request.LoginId}" ) ;
}
#endregion
#region If the user was locked , try set set unlock if Time expired
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & user . IsLocked )
{
int isSuccessful = 0 ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : request . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateOutParam ( pName : "@IsSuccessful" , pType : SqlDbType . Int , pValue : isSuccessful ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.DoUnlockUser" , parameterValues : p ) ;
if ( p [ 2 ] ! = null & & p [ 2 ] . Value ! = null & & p [ 2 ] . Value ! = DBNull . Value )
isSuccessful = Convert . ToInt32 ( p [ 2 ] . Value ) ;
if ( isSuccessful = = 1 )
user . IsLocked = false ;
}
#endregion
#region Keep log for unauthrise access and Set user lock if exceeds max try
if ( ! request . LoginId . ToLower ( ) . Equals ( User . SuperUser_LoginId ) & & maxTryCount > 0 & & user . LoginStatus = = EnumLoginStatus . Unsuccessful )
{
int remainsTry = 0 ;
DateTime ? nextLoginTime = null ;
string tryLoginInfo = $"{request.LoginId}~{password}~13" ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : request . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@TryLoginInfo" , pType : SqlDbType . VarChar , pValue : tryLoginInfo , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MaxTryCount" , pType : SqlDbType . SmallInt , pValue : maxTryCount ) ,
SqlHelperExtension . CreateInParam ( pName : "@LockTime" , pType : SqlDbType . Int , pValue : lockTime ) ,
SqlHelperExtension . CreateOutParam ( pName : "@RemainingTry" , pType : SqlDbType . SmallInt , pValue : remainsTry ) ,
SqlHelperExtension . CreateOutParam ( pName : "@NextLoginTime" , pType : SqlDbType . DateTime , pValue : nextLoginTime ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.LogUnauthorizeAccess" , parameterValues : p ) ;
if ( p [ 5 ] ! = null & & p [ 5 ] . Value ! = null & & p [ 5 ] . Value ! = DBNull . Value )
remainsTry = Convert . ToInt32 ( p [ 5 ] . Value ) ;
if ( p [ 6 ] ! = null & & p [ 6 ] . Value ! = null & & p [ 6 ] . Value ! = DBNull . Value )
nextLoginTime = Convert . ToDateTime ( p [ 6 ] . Value ) ;
if ( remainsTry < = 0 )
{
user . IsLocked = true ;
if ( lockTime < = 0 )
{
user . NextLoginTime = nextLoginTime ;
user . UnsuccessfulMsg = "Please contact with Head office to Unlock" ;
}
else
{
user . NextLoginTime = nextLoginTime ;
user . UnsuccessfulMsg = $"You can Login after {user.NextLoginTime:dd-MMM-yyyy H:mm:ss}" ;
}
}
else
{
user . UnsuccessfulMsg = $"{remainsTry} More attempt{(remainsTry > 1 ? " s " : " ")} remaining" ;
}
}
#endregion
#region If login successful and user is active read module id for this user
if ( user . LoginStatus = = EnumLoginStatus . Success & & user . Status = = EnumStatus . Authorized & & ! user . IsLocked )
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
2026-06-16 15:18:22 +06:00
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
2026-07-08 18:15:24 +06:00
SqlHelperExtension . CreateInParam ( pName : "@LoginTime" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@LogoutTime" , pType : SqlDbType . DateTime , pValue : null )
2026-06-15 18:26:58 +06:00
] ;
2026-06-16 15:18:22 +06:00
_ = tc . ExecuteNonQuerySp ( spName : "dbo.SaveAccessLog" , parameterValues : p ) ;
2026-06-15 18:26:58 +06:00
}
#endregion
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return user ;
}
2026-07-06 17:23:05 +06:00
2026-06-15 18:26:58 +06:00
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < int > LoadNotificationCountAsync ( int userId )
{
int value = 0 ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
value = GetPendingNotifCount ( tc : tc , userId : userId ) ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return value ;
}
/// <summary>
///
/// </summary>
/// <param name="accountId"></param>
/// <returns></returns>
public async Task < FindAccountResponse > FindAccountAsync ( string accountId )
{
FindAccountResponse response = new ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
using ( IDataReader dr = tc . ExecuteReader ( "SELECT UserID, EmailAddress, MobileNo FROM Users WHERE LoginID=%s OR EmailAddress=%s OR MobileNo=%s" , accountId , accountId , accountId ) )
{
if ( dr . Read ( ) )
{
response . UserId = dr . GetInt32 ( 0 ) ;
response . EmailAddress = dr . GetString ( 1 ) ;
response . PhoneNo = dr . GetString ( 2 ) ;
response . Value = true ;
}
dr . Close ( ) ;
}
tc . End ( ) ;
if ( ! response . Value )
{
response . ReturnMessage . Add ( $"[{accountId}] is not a valid Login Id/Email address/Mobile number." ) ;
}
else
{
if ( response . PhoneNo . Length > 8 )
response . PhoneNoMasked = string . Concat ( response . PhoneNo . AsSpan ( 0 , response . PhoneNo . Length - 8 ) , "*****" , response . PhoneNo . AsSpan ( response . PhoneNo . Length - 3 , 3 ) ) ;
int idx = response . EmailAddress . IndexOf ( '@' ) ;
if ( idx ! = - 1 )
{
string firstPart = response . EmailAddress [ . . idx ] ;
if ( firstPart . Length > = 5 )
firstPart = string . Concat ( firstPart . AsSpan ( 0 , firstPart . Length - 5 ) , "*****" ) ;
response . EmailAddressMasked = string . Concat ( firstPart , response . EmailAddress . AsSpan ( idx , response . EmailAddress . Length - idx ) ) ;
}
}
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="authValue"></param>
/// <param name="userId"></param>
/// <returns></returns>
public async Task < bool > ValidateAuthValueAsync ( string authValue , int userId )
{
bool returnValue = false ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@AuthValue" , pType : SqlDbType . VarChar , pValue : authValue , size : 10 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateOutParam ( pName : "@Valid" , pType : SqlDbType . SmallInt , pValue : 0 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.ValidateAuthValue" , parameterValues : p ) ;
if ( p [ 2 ] . Value ! = null & & p [ 2 ] . Value ! = DBNull . Value )
returnValue = Convert . ToInt16 ( p [ 2 ] . Value ) > 0 ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="user"></param>
/// <param name="ipAddress"></param>
/// <param name="createdBy"></param>
/// <returns></returns>
public async Task < bool > AddUserAsync ( NewUserRequest user , string ipAddress , int createdBy )
{
bool returnValue ;
try
{
#region Password Policy if Does not change password on next login
if ( user . AccessStatus ! = EnumAccessStatus . FirstTime )
{
ReadPwdParams ( userId : 0 , loginId : user . LoginId , enfStgPwd : out bool enfStgPwd , minLen : out short minLen , maxLen : out short maxLen , reservedWords : out string reservedWords ) ;
ValidatePwdPolicies ( password : user . Password , minLen : minLen , maxLen : maxLen , enfStgPwd : enfStgPwd , reservedWords : reservedWords ) ;
}
#endregion
int userId = 0 ;
user . Password = EncryptPassword ( password : user . Password ) ;
if ( ! string . IsNullOrEmpty ( user . EmailAddress ) )
user . EmailAddress = user . EmailAddress . Replace ( " " , "" ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserName" , pType : SqlDbType . VarChar , pValue : user . UserName , size : 75 ) ,
SqlHelperExtension . CreateInParam ( pName : "@Designation" , pType : SqlDbType . VarChar , pValue : user . Designation , size : 50 ) ,
SqlHelperExtension . CreateInParam ( pName : "@Password" , pType : SqlDbType . VarChar , pValue : user . Password , size : 75 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MobileNo" , pType : SqlDbType . VarChar , pValue : user . MobileNo , size : 15 ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmailAddress" , pType : SqlDbType . VarChar , pValue : user . EmailAddress , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmployeeId" , pType : SqlDbType . Int , pValue : DataReader . GetNullValue ( user . EmployeeId ) ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmployeeCode" , pType : SqlDbType . VarChar , pValue : DataReader . GetNullValue ( user . EmployeeCode ) , size : 15 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AuthReqAtlogin" , pType : SqlDbType . SmallInt , pValue : user . AuthReqAtlogin ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AuthMethod" , pType : SqlDbType . SmallInt , pValue : user . AuthMethod ) ,
SqlHelperExtension . CreateInParam ( pName : "@DBOnStartup" , pType : SqlDbType . SmallInt , pValue : user . DbOnStartup ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@Status" , pType : SqlDbType . SmallInt , pValue : user . Status ) ,
SqlHelperExtension . CreateInParam ( pName : "@SeqId" , pType : SqlDbType . SmallInt , pValue : user . SeqId ) ,
SqlHelperExtension . CreateInParam ( pName : "@CanUseAtnSys" , pType : SqlDbType . SmallInt , pValue : user . CanUseAttendanceSystem ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ViewToAll" , pType : SqlDbType . SmallInt , pValue : user . ViewToAll ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AccessStatus" , pType : SqlDbType . SmallInt , pValue : user . AccessStatus ) ,
SqlHelperExtension . CreateInParam ( pName : "@NeverExpire" , pType : SqlDbType . SmallInt , pValue : user . NeverExpire ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@DAMultiLogin" , pType : SqlDbType . SmallInt , pValue : user . DisallowMultiLogin ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@CreatedBy" , pType : SqlDbType . Int , pValue : createdBy ) ,
SqlHelperExtension . CreateOutParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.InsertUser" , parameterValues : p ) ;
userId = ( p [ 20 ] ? . Value ! = null & & p [ 20 ] ? . Value ! = DBNull . Value ) ? Convert . ToInt32 ( p [ 20 ] . Value ) : 0 ;
if ( user . GroupIds ! = null & & user . GroupIds . Count > 0 & & userId > 0 )
{
List < int > ownerGroupsIds = [ ] ;
if ( createdBy = = User . SuperUser_Id )
{
ownerGroupsIds . AddRange ( user . GroupIds ) ;
}
else
{
using IDataReader dr = tc . ExecuteReader ( "SELECT GroupId FROM Groups WHERE (CreatedBy=%n OR ViewToAll=1)" , createdBy ) ;
while ( dr . Read ( ) )
{
ownerGroupsIds . Add ( dr . GetInt32 ( 0 ) ) ;
}
dr . Close ( ) ;
}
StringBuilder sb = new ( ) ;
foreach ( int groupId in user . GroupIds )
{
if ( ! ownerGroupsIds . Contains ( groupId ) )
continue ;
sb . Append ( $"INSERT INTO UserGroups(UserId,GroupId) VALUES({userId},{groupId});" ) ;
}
_ = tc . ExecuteNonQuery ( commandText : sb . ToString ( ) ) ;
}
tc . End ( ) ;
#region Copy File
try
{
string destFileName = System . IO . Path . Combine ( _settings . ProfileImageFolder , $"{userId}.png" ) ;
string sourceFileName = System . IO . Path . Combine ( _settings . ProfileImageFolder , "default-user.png" ) ;
if ( System . IO . File . Exists ( path : sourceFileName ) )
{
System . IO . File . Copy ( sourceFileName : sourceFileName , destFileName : destFileName ) ;
}
}
catch
{
//Do nothing
}
#endregion
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="user"></param>
/// <param name="ipAddress"></param>
/// <param name="modifiedBy"></param>
/// <returns></returns>
public async Task < bool > EditUserAsync ( UserRequest user , string ipAddress , int modifiedBy )
{
bool returnValue = false ;
try
{
if ( ! string . IsNullOrEmpty ( user . EmailAddress ) )
user . EmailAddress = user . EmailAddress . Replace ( " " , "" ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserName" , pType : SqlDbType . VarChar , pValue : user . UserName , size : 75 ) ,
SqlHelperExtension . CreateInParam ( pName : "@Designation" , pType : SqlDbType . VarChar , pValue : user . Designation , size : 50 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MobileNo" , pType : SqlDbType . VarChar , pValue : user . MobileNo , size : 15 ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmailAddress" , pType : SqlDbType . VarChar , pValue : user . EmailAddress ? ? string . Empty , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AuthReqAtlogin" , pType : SqlDbType . SmallInt , pValue : user . AuthReqAtlogin ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AuthMethod" , pType : SqlDbType . SmallInt , pValue : user . AuthMethod ) ,
SqlHelperExtension . CreateInParam ( pName : "@AuthKey" , pType : SqlDbType . VarChar , pValue : user . AuthKey , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@DBOnStartup" , pType : SqlDbType . SmallInt , pValue : user . DbOnStartup ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@Status" , pType : SqlDbType . SmallInt , pValue : user . Status ) ,
SqlHelperExtension . CreateInParam ( pName : "@SeqId" , pType : SqlDbType . SmallInt , pValue : user . SeqId ) ,
SqlHelperExtension . CreateInParam ( pName : "@CanUseAtnSys" , pType : SqlDbType . SmallInt , pValue : user . CanUseAttendanceSystem ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ViewToAll" , pType : SqlDbType . SmallInt , pValue : user . ViewToAll ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@AccessStatus" , pType : SqlDbType . SmallInt , pValue : user . AccessStatus ) ,
SqlHelperExtension . CreateInParam ( pName : "@NeverExpire" , pType : SqlDbType . SmallInt , pValue : user . NeverExpire ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@DAMultiLogin" , pType : SqlDbType . SmallInt , pValue : user . DisallowMultiLogin ? 1 : 0 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ModifiedBy" , pType : SqlDbType . Int , pValue : modifiedBy ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UpdateUser" , parameterValues : p ) ;
if ( user . GroupIds ! = null & & user . GroupIds . Count > 0 & & user . UserId > 0 )
{
List < int > ownerGroupsIds = [ ] ;
if ( modifiedBy = = User . SuperUser_Id )
{
ownerGroupsIds . AddRange ( user . GroupIds ) ;
}
else
{
using IDataReader dr = tc . ExecuteReader ( "SELECT GroupId FROM Groups WHERE (CreatedBy=%n OR ViewToAll=1)" , modifiedBy ) ;
while ( dr . Read ( ) )
{
ownerGroupsIds . Add ( dr . GetInt32 ( 0 ) ) ;
}
dr . Close ( ) ;
}
StringBuilder sb = new ( ) ;
foreach ( int groupId in user . GroupIds )
{
if ( ! ownerGroupsIds . Contains ( groupId ) )
continue ;
sb . Append ( $"INSERT INTO UserGroups(UserId,GroupId) VALUES({user.UserId},{groupId});" ) ;
}
_ = tc . ExecuteNonQuery ( commandText : sb . ToString ( ) ) ;
}
tc . End ( ) ;
#region Copy File
try
{
string destFileName = System . IO . Path . Combine ( _settings . ProfileImageFolder , $"{user.UserId}.png" ) ;
string sourceFileName = System . IO . Path . Combine ( _settings . ProfileImageFolder , "default-user.png" ) ;
if ( System . IO . File . Exists ( path : sourceFileName ) & & ! System . IO . File . Exists ( path : destFileName ) )
{
System . IO . File . Copy ( sourceFileName : sourceFileName , destFileName : destFileName ) ;
}
}
catch
{
//Do nothing
}
#endregion
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="deletedBy"></param>
/// <returns></returns>
public async Task < bool > DeleteUserAsync ( int userId , int deletedBy )
{
bool returnValue ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@DeletedBy" , pType : SqlDbType . Int , pValue : deletedBy ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.DeleteUser" , parameterValues : p ) ;
tc . End ( ) ;
#region Delete File
try
{
string fileSpec = System . IO . Path . Combine ( _settings . ProfileImageFolder , $"{userId}.png" ) ;
if ( System . IO . File . Exists ( path : fileSpec ) )
System . IO . File . Delete ( path : fileSpec ) ;
}
catch
{
//Do nothing
}
#endregion
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="loginId"></param>
/// <param name="unlockedBy"></param>
/// <returns></returns>
public async Task < bool > UnlockUserAsync ( int userId , string loginId , int unlockedBy )
{
bool returnValue ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : loginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UnlockedBy" , pType : SqlDbType . Int , pValue : unlockedBy )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UnlockUser" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="ipAddress"></param>
/// <param name="changedBy"></param>
/// <returns></returns>
public async Task < bool > ResetPasswordAsync ( int userId , string newPassword , string ipAddress , int changedBy )
{
bool returnValue = false ;
try
{
try
{
newPassword = EncryptPassword ( password : newPassword ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@NewPwd" , pType : SqlDbType . VarChar , pValue : newPassword , size : 75 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastPwds" , pType : SqlDbType . VarChar , pValue : string . Empty , size : 700 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastPwdChgDate" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@PwdExpireDate" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@ChangedBy" , pType : SqlDbType . Int , pValue : changedBy ) ,
SqlHelperExtension . CreateInParam ( pName : "@ResetPwd" , pType : SqlDbType . SmallInt , pValue : 1 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UpdateUserPassword" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="ipAddress"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task < bool > SendPasswordAsync ( int userId , string newPassword , string ipAddress )
{
bool returnValue = false ;
try
{
newPassword = EncryptPassword ( password : newPassword ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@NewPwd" , pType : SqlDbType . VarChar , pValue : newPassword , size : 75 ) ,
SqlHelperExtension . CreateInParam ( pName : "LastPwds" , pType : SqlDbType . VarChar , pValue : string . Empty , size : 700 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastPwdChgDate" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@PwdExpireDate" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@ChangedBy" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@ResetPwd" , pType : SqlDbType . SmallInt , pValue : 1 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UpdateUserPassword" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="oldPassword"></param>
/// <param name="ipAddress"></param>
/// <param name="changedBy"></param>
/// <returns></returns>
public async Task < bool > ChangePasswordAsync ( int userId , string oldPassword , string newPassword , string ipAddress , int changedBy )
{
bool returnValue = false ;
try
{
bool loginIdCantPwd = false ;
DateTime ? lastPassChgDate = null ;
List < string > actPwdHistories = [ ] ;
Queue < string > pwdHistories = new ( ) ;
EnumAccessStatus accessStatus = EnumAccessStatus . LoggedOut ;
short pwdMinLen = 0 , pwdMaxLen = 0 , daLastPwds = 0 , expiryDays = 0 ;
bool neverExpire = false , enfStgPwd = false , prvntAtckPwdReuse = false ;
string loginId = string . Empty , password = string . Empty , lastPasswords = string . Empty , reservedWords = string . Empty ;
#region Reading Data from DB
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
using IDataReader dr = tc . ExecuteReader ( "SELECT A.LoginId, A.Password, A.LastPasswords, A.LastPassChgDate, A.NeverExpire, A.AccessStatus,"
+ " B.EnfStgPwd, B.PwdMinLen, B.PwdMaxLen, B.ExpiryDays, B.DALastPwds, B.PwdRsvdWords, B.loginIdCantPwd, B.PrvntAtckPwdReuse"
+ " FROM Users A LEFT OUTER JOIN ThisSystem B ON A.UserID=A.UserID WHERE A.UserID=%n" , userId ) ;
if ( dr . Read ( ) )
{
loginId = dr . GetString ( 0 ) ;
password = dr . GetString ( 1 ) ;
lastPasswords = dr . IsDBNull ( 2 ) ? string . Empty : dr . GetString ( 2 ) ;
lastPassChgDate = dr . IsDBNull ( 3 ) ? null : dr . GetDateTime ( 3 ) ;
neverExpire = ! dr . IsDBNull ( 4 ) & & dr . GetInt16 ( 4 ) > 0 ;
accessStatus = ( EnumAccessStatus ) dr . GetInt16 ( 5 ) ;
enfStgPwd = ! dr . IsDBNull ( 6 ) & & dr . GetInt16 ( 6 ) > 0 ;
pwdMinLen = dr . IsDBNull ( 7 ) ? Convert . ToInt16 ( 0 ) : dr . GetInt16 ( 7 ) ;
pwdMaxLen = dr . IsDBNull ( 8 ) ? Convert . ToInt16 ( 30 ) : dr . GetInt16 ( 8 ) ;
expiryDays = dr . IsDBNull ( 9 ) ? Convert . ToInt16 ( 0 ) : dr . GetInt16 ( 9 ) ;
daLastPwds = dr . IsDBNull ( 10 ) ? Convert . ToInt16 ( 0 ) : dr . GetInt16 ( 10 ) ;
reservedWords = dr . IsDBNull ( 11 ) ? string . Empty : dr . GetString ( 11 ) ;
loginIdCantPwd = ! dr . IsDBNull ( 12 ) & & dr . GetInt16 ( 12 ) ! = 0 ;
prvntAtckPwdReuse = ! dr . IsDBNull ( 13 ) & & dr . GetInt16 ( 13 ) ! = 0 ;
}
dr . Close ( ) ;
tc . End ( ) ;
if ( loginIdCantPwd & & ! string . IsNullOrEmpty ( loginId ) )
{
reservedWords = string . IsNullOrEmpty ( reservedWords ) ? loginId : $"{reservedWords},{loginId}" ;
}
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
#endregion
#region Validation
oldPassword = EncryptPassword ( password : oldPassword ) ;
if ( ! oldPassword . Equals ( password ) )
throw new InvalidOperationException ( "Old Password does not match with system." ) ;
#region Password Histories
if ( ! string . IsNullOrEmpty ( lastPasswords ) & & ! string . IsNullOrWhiteSpace ( lastPasswords ) )
{
string [ ] pwds = lastPasswords . Split ( ',' ) ;
foreach ( string pwd in pwds )
{
pwdHistories . Enqueue ( pwd ) ;
}
}
#endregion
#region Actual Password Histories
string [ ] pwdsHists = [ . . pwdHistories ] ;
if ( daLastPwds > 0 & & pwdsHists . Length > 0 )
{
for ( int idx = pwdsHists . Length - 1 ; idx > = 0 ; idx - - )
{
if ( ! actPwdHistories . Contains ( pwdsHists [ idx ] ) & & actPwdHistories . Count < = daLastPwds )
actPwdHistories . Add ( pwdsHists [ idx ] ) ;
}
}
#endregion
if ( lastPassChgDate . HasValue & & prvntAtckPwdReuse & & accessStatus ! = EnumAccessStatus . FirstTime & & lastPassChgDate . Value . Date > = DateTime . Today . Date )
{
throw new InvalidOperationException ( "Password should be at least one day old to change again." ) ;
}
CheckPasswordHistory ( password : newPassword , minLen : pwdMinLen , maxLen : pwdMaxLen , enfStgPwd : enfStgPwd , reservedWords : reservedWords , daLastPwds : daLastPwds , pwdHistories : pwdHistories , actPwdHistories : actPwdHistories ) ;
#endregion
#region Updateing Data
if ( pwdHistories . ToArray ( ) . Length > 0 )
lastPasswords = string . Join ( "," , [ . . pwdHistories ] ) ;
DateTime ? expireDate = null ;
lastPassChgDate = DateTime . Now ;
if ( ! neverExpire & & expiryDays > 0 )
expireDate = DateTime . Now . AddDays ( expiryDays ) ;
try
{
newPassword = EncryptPassword ( password : newPassword ) ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@NewPwd" , pType : SqlDbType . VarChar , pValue : newPassword , size : 75 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastPwds" , pType : SqlDbType . VarChar , pValue : lastPasswords , size : 700 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastPwdChgDate" , pType : SqlDbType . DateTime , pValue : lastPassChgDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@PwdExpireDate" , pType : SqlDbType . DateTime , pValue : expireDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@ChangedBy" , pType : SqlDbType . Int , pValue : changedBy ) ,
SqlHelperExtension . CreateInParam ( pName : "@ResetPwd" , pType : SqlDbType . SmallInt , pValue : 0 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UpdateUserPassword" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
#endregion
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="menuLayout"></param>
/// <param name="themeName"></param>
/// <param name="schemeName"></param>
/// <returns></returns>
public async Task < bool > UpdateMyThemeAsync ( int userId , string menuLayout , string themeName , string schemeName )
{
bool returnValue = false ;
try
{
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@MenuLayout" , pType : SqlDbType . VarChar , pValue : menuLayout , size : 15 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ThemeName" , pType : SqlDbType . VarChar , pValue : themeName , size : 15 ) ,
SqlHelperExtension . CreateInParam ( pName : "@SchemeName" , pType : SqlDbType . VarChar , pValue : schemeName , size : 10 ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UpdateMyTheme" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="address"></param>
/// <param name="contactNo"></param>
/// <param name="modifiedBy"></param>
/// <param name="emplyeeId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < bool > UpdateMyInfoAsync ( string address , string contactNo , int modifiedBy , int emplyeeId )
{
bool returnValue = false ;
try
{
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@Address" , pType : SqlDbType . VarChar , pValue : address , size : 120 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ContactNo" , pType : SqlDbType . VarChar , pValue : contactNo , size : 25 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ModifiedBy" , pType : SqlDbType . Int , pValue : modifiedBy ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmployeeId" , pType : SqlDbType . Int , pValue : emplyeeId )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UpdateMyInfo" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="clientType"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < UserAttributesResponse > GetAttributesAsync ( int userId , int clientType )
{
UserAttributesResponse response = new ( ) { ReturnStatus = 200 } ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
using ( IDataReader dr = tc . ExecuteReader ( "SELECT LoginId FROM Users WHERE UserId=%n" , userId ) )
{
if ( dr . Read ( ) )
{
response = new UserAttributesResponse
{
UserId = userId ,
LoginId = dr . GetString ( 0 ) ,
ReturnStatus = 200 ,
UkIds = [ ] ,
} ;
}
dr . Close ( ) ;
}
#region Client & Projects
if ( response . UserId > 0 )
{
using IDataReader dr = tc . ExecuteReader ( $"SELECT ProjectId, ClientId FROM UserClients WHERE UserId=%n AND ProjectId IS {(clientType == 1 ? " NOT " : " ")}NULL" , response . UserId ) ;
while ( dr . Read ( ) )
{
string ukId = $"{(dr.IsDBNull(0) ? 0 : dr.GetInt32(0))}|{dr.GetInt32(1)}" ;
response . UkIds . Add ( ukId ) ;
}
dr . Close ( ) ;
}
response . HasSetup = response . UkIds . Count > 0 ;
#endregion
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="clientType"></param>
/// <param name="ipAddress"></param>
/// <param name="attributeSetBy"></param>
/// <param name="ukIds"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="clientType"></param>
/// <param name="deletedBy"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < bool > DeleteAttributesAsync ( int userId , int clientType , int deletedBy )
{
bool returnValue ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@ClientType" , pType : SqlDbType . SmallInt , pValue : clientType ) ,
SqlHelperExtension . CreateInParam ( pName : "@DeletedBy" , pType : SqlDbType . Int , pValue : deletedBy )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.DeleteUserAttributes" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
2026-06-16 11:36:11 +06:00
//public async Task<UserSearchResponse> GetUsersAsync(UserSearchRequest request, int userId)
//{
// UserSearchResponse response = new();
// try
// {
// string andClause = string.Empty;
// if (!string.IsNullOrEmpty(request.Criteria))
// {
// string criteria = request.Criteria.Replace("'", "''");
// andClause = $" AND (LoginID='{criteria}' OR MobileNo='{criteria}' OR EmailAddress='{criteria}' OR UserName LIKE '%{criteria}%' OR Designation LIKE '%{criteria}%')";
// }
// if (request.Status > 0)
// andClause += SQLParser.MakeSQL(" AND Status=%n", request.Status);
// if (request.CheckOwner)
// andClause += SQLParser.MakeSQL(" AND (CreatedBy=%n OR ViewToAll=1)", userId);
// string sortField = request.SortField switch
// {
// "userName" => "UserName",
// "designation" => "Designation",
// "mobileNo" => "MobileNo",
// "emailAddress" => "EmailAddress",
// "statusDetail" => "Status",
// "loginId" => "LoginId",
// _ => "SeqId, LoginId"
// };
// string sortOrder = request.SortOrder switch
// {
// "desc" => "DESC",
// _ => "ASC",
// };
// string commandText = request.Skip + request.PageSize <= 0 ?
// SQLParser.MakeSQL("SELECT UserId, LoginId, UserName, Designation, MobileNo, EmailAddress, Status, SeqId, IsLocked, CanUseAtnSys, Password,"
// + " COUNT(*) OVER() AS TotalRows FROM Users WHERE UserId!=-9%q ORDER BY %q %q", andClause, sortField, sortOrder)
// : SQLParser.MakeSQL("SELECT A.UserId, A.LoginId, A.UserName, A.Designation, A.MobileNo, A.EmailAddress, A.Status, A.SeqId, A.IsLocked,"
// + " A.CanUseAtnSys, A.Password, A.TotalRows FROM(SELECT UserId, LoginId, UserName, Designation, MobileNo, EmailAddress, Status, SeqId,"
// + " IsLocked, CanUseAtnSys, Password, ROW_NUMBER() OVER(ORDER BY %q %q) AS RN, COUNT(*) OVER() AS TotalRows FROM Users WHERE UserId!=-9%q) A"
// + " WHERE A.RN>%n AND A.RN<=%n", sortField, sortOrder, andClause, request.Skip, request.Skip + request.PageSize);
// using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
// try
// {
// int totalRows = 0;
// using IDataReader dr = tc.ExecuteReader(commandText: commandText);
// while (dr.Read())
// {
// UserGetResponse item = new()
// {
// UserId = dr.GetInt32(0),
// LoginId = dr.GetString(1),
// UserName = dr.GetString(2),
// Designation = dr.GetString(3),
// MobileNo = dr.GetString(4),
// EmailAddress = dr.GetString(5),
// Status = (EnumStatus)dr.GetInt16(6),
// SeqId = dr.GetInt16(7),
// IsLocked = !dr.IsDBNull(8) && dr.GetInt16(8) != 0,
// CanUseAttendanceSystem = !dr.IsDBNull(9) && dr.GetInt16(9) != 0,
// };
// totalRows = dr.GetInt32(11);
// }
// dr.Close();
// response.TotalRows = totalRows;
// tc.End();
// response.ReturnStatus = 200;
// }
// catch (Exception ie)
// {
// tc?.HandleError();
// throw DBCustomError.GenerateCustomError(ie);
// }
// }
// catch (Exception e)
// {
// throw new InvalidOperationException(e.Message, e);
// }
// return response;
//}
2026-06-15 18:26:58 +06:00
/// <summary>
///
/// </summary>
/// <param name="teamSpaceIds"></param>
/// <param name="projectId"></param>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < UserBasicInfoResponse > GetUsersByTeamSpaceAsync ( string teamSpaceIds , int projectId , int userId )
{
UserBasicInfoResponse response = new ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
string andClause = string . Empty ;
if ( userId > 0 )
{
andClause = $" AND UserID={userId}" ;
}
else
{
if ( ! string . IsNullOrEmpty ( teamSpaceIds ) )
{
andClause = $" AND UserID IN(SELECT UserId FROM TeamSpaceUsers WHERE TeamSpaceId IN({teamSpaceIds}))" ;
}
if ( projectId > 0 )
{
andClause + = $" AND UserID IN(SELECT UserId FROM TeamSpaceUserProjects WHERE ProjectId={projectId})" ;
}
}
string commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8{andClause} ORDER BY SeqId, UserName" ;
using IDataReader dr = tc . ExecuteReader ( commandText : commandText ) ;
while ( dr . Read ( ) )
{
UserBasicInfo item = new ( )
{
UserId = dr . GetInt32 ( 0 ) ,
LoginId = dr . GetString ( 1 ) ,
UserName = dr . GetString ( 2 ) ,
Designation = dr . GetString ( 3 ) ,
} ;
response . Value . Add ( item ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="applyFilter"></param>
/// <param name="teamSpaceIds"></param>
/// <param name="projectId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < UserBasicInfoResponse > GetUsersBasicAsync ( bool applyFilter , string teamSpaceIds , int projectId )
{
UserBasicInfoResponse response = new ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
string commandText ;
if ( applyFilter )
{
if ( ! string . IsNullOrEmpty ( teamSpaceIds ) )
{
commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id}"
+ $" AND Status=8 AND UserID IN(SELECT UserId FROM TeamSpaceUsers WHERE TeamSpaceId IN({teamSpaceIds}))" ;
}
else
{
commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8" ;
}
if ( projectId > 0 )
{
commandText + = $" AND UserID IN(SELECT UserId FROM UserClients WHERE ProjectID={projectId})" ;
}
}
else
{
commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8" ;
}
commandText + = " ORDER BY SeqId, UserName" ;
using IDataReader dr = tc . ExecuteReader ( commandText : commandText ) ;
while ( dr . Read ( ) )
{
UserBasicInfo item = new ( )
{
UserId = dr . GetInt32 ( 0 ) ,
LoginId = dr . GetString ( 1 ) ,
UserName = dr . GetString ( 2 ) ,
Designation = dr . GetString ( 3 ) ,
} ;
response . Value . Add ( item ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="createdBy"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task < UserForceLogoutResponse > GetForceLogoutUsersAsync ( int createdBy )
{
UserForceLogoutResponse response = new ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
string commandText ;
if ( createdBy = = User . SuperUser_Id )
commandText = $"SELECT UserID, LoginID, UserName FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8 ORDER BY LoginID" ;
else
commandText = $"SELECT UserID, LoginID, UserName FROM Users WHERE (CreatedBy={createdBy} OR ViewToAll=1) AND Status=8 ORDER BY LoginID" ;
using IDataReader dr = tc . ExecuteReader ( commandText : commandText ) ;
while ( dr . Read ( ) )
{
UserForceLogout item = new ( )
{
UserId = dr . GetInt32 ( 0 ) ,
LoginId = dr . GetString ( 1 ) ,
UserName = dr . GetString ( 2 )
} ;
response . Value . Add ( item ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < UserBasicInfoResponse > GetAttendanceUsersAsync ( int userId )
{
UserBasicInfoResponse response = new ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
string andClause = userId > 0 ? $" AND UserID={userId}" : string . Empty ;
using IDataReader dr = tc . ExecuteReader ( commandText : $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE EmployeeId IS NOT NULL AND Status=8{andClause} ORDER BY SeqId, UserName" ) ;
while ( dr . Read ( ) )
{
UserBasicInfo item = new ( )
{
UserId = dr . GetInt32 ( 0 ) ,
LoginId = dr . GetString ( 1 ) ,
UserName = dr . GetString ( 2 ) ,
Designation = dr . GetString ( 3 ) ,
} ;
response . Value . Add ( item ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="userIds"></param>
/// <param name="ipAddress"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task < bool > ForceLogoutNowAsync ( List < int > userIds , string ipAddress )
{
bool returnValue ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserIDs" , pType : SqlDbType . VarChar , pValue : string . Join ( "," , userIds . ToArray ( ) ) , size : 8000 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.DoForceLogout" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task < UserGetResponse > GetUserAsync ( int userId )
{
UserGetResponse response = new ( ) { ReturnStatus = 200 } ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
using ( IDataReader dr = tc . ExecuteReader ( "SELECT LoginId, UserName, Designation, MobileNo, EmailAddress, IsLocked, Status,"
+ " AccessStatus, NeverExpire, AuthReqAtlogin, AuthMethod, DBOnStartup, DAMultiLogin, EmployeeCode, SeqId, CanUseAtnSys, ViewToAll"
+ " FROM Users WHERE UserId=%n" , userId ) )
{
if ( dr . Read ( ) )
{
response = new UserGetResponse
{
UserId = userId ,
LoginId = dr . GetString ( 0 ) ,
UserName = dr . GetString ( 1 ) ,
Designation = dr . GetString ( 2 ) ,
MobileNo = dr . GetString ( 3 ) ,
EmailAddress = dr . GetString ( 4 ) ,
IsLocked = ! dr . IsDBNull ( 5 ) & & dr . GetInt16 ( 5 ) > 0 ,
Status = ( EnumStatus ) dr . GetInt16 ( 6 ) ,
AccessStatus = ( EnumAccessStatus ) dr . GetInt16 ( 7 ) ,
NeverExpire = ! dr . IsDBNull ( 8 ) & & dr . GetInt16 ( 8 ) ! = 0 ,
AuthRequiredAtLogin = ! dr . IsDBNull ( 9 ) & & dr . GetInt16 ( 9 ) ! = 0 ,
AuthMethod = ( EnumAuthenticationMethod ) dr . GetInt16 ( 10 ) ,
DbOnStartup = ! dr . IsDBNull ( 11 ) & & dr . GetInt16 ( 11 ) ! = 0 ,
DisallowMultiLogin = ! dr . IsDBNull ( 12 ) & & dr . GetInt16 ( 12 ) ! = 0 ,
EmployeeCode = dr . IsDBNull ( 13 ) ? string . Empty : dr . GetString ( 13 ) ,
SeqId = dr . GetInt16 ( 14 ) ,
CanUseAttendanceSystem = ! dr . IsDBNull ( 15 ) & & dr . GetInt16 ( 15 ) ! = 0 ,
ViewToAll = ! dr . IsDBNull ( 16 ) & & dr . GetInt16 ( 16 ) ! = 0 ,
ReturnStatus = 200
} ;
}
dr . Close ( ) ;
}
response . GroupIds = [ ] ;
using ( IDataReader dr = tc . ExecuteReader ( "SELECT GroupId FROM UserGroups WHERE UserID=%n" , userId ) )
{
while ( dr . Read ( ) )
{
response . GroupIds . Add ( dr . GetInt32 ( 0 ) ) ;
}
dr . Close ( ) ;
}
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task < UserProfileResponse > GetUserProfileAsync ( int userId )
{
UserProfileResponse response = new ( ) { ReturnStatus = 200 } ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
int employeeId = 0 ;
using ( IDataReader dr = tc . ExecuteReader ( "SELECT LoginId, UserName, Designation, LastPassChgDate, ExpireDate, EmployeeId FROM Users WHERE UserId=%n" , userId ) )
{
if ( dr . Read ( ) )
{
response = new UserProfileResponse
{
UserId = userId ,
LoginId = dr . GetString ( 0 ) ,
UserName = dr . GetString ( 1 ) ,
Designation = dr . GetString ( 2 ) ,
PwdLastChangedTime = dr . IsDBNull ( 3 ) ? null : dr . GetDateTime ( 3 ) ,
NextPwdDate = dr . IsDBNull ( 4 ) ? null : dr . GetDateTime ( 4 ) ,
ReturnStatus = 200
} ;
employeeId = dr . IsDBNull ( 5 ) ? 0 : dr . GetInt32 ( 5 ) ;
}
dr . Close ( ) ;
}
if ( employeeId > 0 )
{
using IDataReader dr = tc . ExecuteReader ( "SELECT Address, ContactNo FROM Employees WHERE EmployeeId=%n" , employeeId ) ;
if ( dr . Read ( ) )
{
response . Address = dr . GetString ( 0 ) ;
response . ContactNo = dr . GetString ( 1 ) ;
}
dr . Close ( ) ;
}
response . LoginHistories = [ ] ;
using ( IDataReader dr = tc . ExecuteReader ( "SELECT TOP 10 LoginIPAddress, LoginTime, LogoutIPAddress, LogoutTime"
+ " FROM AccessLog WHERE UserID=%n ORDER BY LoginTime DESC" , userId ) )
{
int slNo = 0 ;
while ( dr . Read ( ) )
{
slNo + + ;
LoginHistory item = new ( )
{
SlNo = slNo ,
LoginIp = dr . GetString ( 0 ) ,
LoginTime = dr . GetDateTime ( 1 ) ,
LogoutIp = dr . IsDBNull ( 2 ) ? string . Empty : dr . GetString ( 2 ) ,
LogoutTime = dr . IsDBNull ( 3 ) ? null : dr . GetDateTime ( 3 ) ,
} ;
response . LoginHistories . Add ( item : item ) ;
}
dr . Close ( ) ;
}
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task < MenuResponse > GetUserPermissionsAsync ( int userId )
{
MenuResponse response = new ( ) { Item = new ( ) { Items = [ ] } } ;
MenuItem pi = new ( ) { Label = "User Profile" , Icon = "fa fa-user-md" , RouterLink = string . Empty , Items = [ ] } ;
pi . Items . Add ( new ( ) { Label = "My Profile" , Icon = "fa fa-user" , RouterLink = "/myprofile" } ) ;
pi . Items . Add ( new ( ) { Label = "Change My Password" , Icon = "fa fa-unlock" , RouterLink = "/changemypwd" } ) ;
pi . Items . Add ( new ( ) { Label = "Change My Theme" , Icon = "fa fa-user" , RouterLink = "/changemytheme" } ) ;
pi . Items . Add ( new ( ) { Label = "WhatsApp Message" , Icon = "fa fa-whatsapp" , RouterLink = "/sendwhatsappmsg" } ) ;
pi . Items . Add ( new ( ) { Label = "Access Log" , Icon = "fa fa-list-alt" , RouterLink = "/accesslog" } ) ;
response . Item . Items . Add ( pi ) ;
List < GroupPermission > pmns = [ ] ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
SqlParameter [ ] p = [ SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ] ;
using IDataReader dr = tc . ExecuteReaderSp ( spName : "dbo.GetUserPermissions" , parameterValues : p ) ;
while ( dr . Read ( ) )
{
GroupPermission item = new ( )
{
ModuleId = dr . GetString ( 0 ) ,
AllowSelect = dr . GetInt16 ( 1 ) ! = 0 ,
AllowAdd = dr . GetInt16 ( 2 ) ! = 0 ,
AllowEdit = dr . GetInt16 ( 3 ) ! = 0 ,
AllowDelete = dr . GetInt16 ( 4 ) ! = 0
} ;
pmns . Add ( item ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
#region Making Hierarchy
List < GroupPermission > items = [ ] ;
List < GroupPermission > fullMenu = GlobalFunctions . BuildMenu ( ) ;
IEnumerable < GroupPermission > data = fullMenu . Where ( x = > ( string . IsNullOrEmpty ( x . ParentId ) | | string . IsNullOrWhiteSpace ( x . ParentId ) ) & & x . Visible & & pmns . Where ( y = > y . AllowSelect ) . Select ( z = > z . ModuleId ) . Contains ( x . ModuleId ) ) ;
foreach ( GroupPermission datum in data )
{
MakeHierarchy ( parent : datum , data : fullMenu , pmns : pmns ) ;
}
items . AddRange ( data ) ;
if ( _menuSettings ? . MenuItems ? . Count > 0 )
{
foreach ( GroupPermission src in items )
{
MenuItem dst = src . Copy ( ) ;
dst . Label = _menuSettings . GetItem ( src . ModuleId , src . ModuleName ) . Value ;
response . Item . Items . Add ( dst ) ;
CopyHierarchy ( src : src , dst : dst ) ;
}
}
else
{
foreach ( GroupPermission src in items )
{
MenuItem dst = src . Copy ( ) ;
response . Item . Items . Add ( dst ) ;
CopyHierarchy ( src : src , dst : dst ) ;
}
}
items . Clear ( ) ;
#endregion
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="canViewLeave"></param>
/// <param name="canViewLate"></param>
/// <param name="canViewClientVisit"></param>
/// <param name="canViewHomeOffice"></param>
/// <param name="viewAll"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
/// <summary>
///
/// </summary>
/// <param name="poId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="id"></param>
/// <param name="documentOf"></param>
/// <param name="orgFileName"></param>
/// <param name="fileName"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task < bool > UploadDocumentAsync ( int userId , int id , int documentOf , string orgFileName , string fileName )
{
bool returnValue = false ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserID" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@Id" , pType : SqlDbType . Int , pValue : id ) ,
SqlHelperExtension . CreateInParam ( pName : "@DocumentOf" , pType : SqlDbType . SmallInt , pValue : documentOf ) ,
SqlHelperExtension . CreateInParam ( pName : "@OrgFileName" , pType : SqlDbType . VarChar , pValue : orgFileName , size : 200 ) ,
SqlHelperExtension . CreateInParam ( pName : "@FileName" , pType : SqlDbType . VarChar , pValue : fileName , size : 100 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.UploadDocument" , parameterValues : p ) ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
/// <summary>
///
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="userId"></param>
/// <param name="logId"></param>
/// <param name="attendanceLogout"></param>
/// <param name="loginId"></param>
/// <param name="localIp"></param>
/// <param name="macAddress"></param>
/// <param name="hostName"></param>
/// <param name="logoutRemarks"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < bool > LogoutAsync ( string ipAddress , int userId , int logId , bool attendanceLogout , string loginId , string localIp , string macAddress , string hostName , string logoutRemarks )
{
bool returnValue = false ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p ;
#region Attendance Logout and Valid Ip Address
if ( attendanceLogout & & userId ! = User . SuperUser_Id )
{
string errMsg = string . Empty ;
p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserID" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : loginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : localIp , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@MacAddress" , pType : SqlDbType . VarChar , pValue : macAddress , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@HostName" , pType : SqlDbType . VarChar , pValue : hostName , size : 100 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LogoutRemarks" , pType : SqlDbType . VarChar , pValue : logoutRemarks , size : 50 ) ,
SqlHelperExtension . CreateOutParam ( pName : "@ErrMsg" , pType : SqlDbType . VarChar , pValue : errMsg , size : 300 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.LogoutFromAttendance" , parameterValues : p ) ;
errMsg = ( p [ 6 ] = = null | | p [ 6 ] . Value = = null | | p [ 6 ] . Value = = DBNull . Value ) ? string . Empty : Convert . ToString ( p [ 6 ] . Value ) ;
if ( ! string . IsNullOrEmpty ( errMsg ) )
{
throw new InvalidOperationException ( errMsg ) ;
}
}
#endregion
//Keep access history
p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserID" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@Status" , pType : SqlDbType . TinyInt , pValue : 3 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LogID" , pType : SqlDbType . Int , pValue : logId ) ,
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.CreateAccessLog" , parameterValues : p ) ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
2026-07-06 17:23:05 +06:00
public async Task < AuthLogoutResponse > LogoutAsync ( AuthLogoutRequest request , string ipAddress )
{
AuthLogoutResponse response = null ;
try
{
User user = null ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
DateTime sysDate = DateTime . Today . Date ;
string appVer = string . Empty , alParams = string . Empty ;
#region Read User data using authentication data
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . NVarChar , pValue : request . LoginId )
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetUserByLogin" , parameterValues : p ) )
{
if ( dr . Read ( ) )
{
user = new User ( ) ;
{
user . UserId = dr . GetInt32 ( 0 ) ;
user . Password = dr . GetString ( 1 ) ;
user . LoginId = dr . GetString ( 2 ) ;
user . UserName = dr . GetString ( 3 ) ;
user . Status = ( EnumStatus ) dr . GetInt32 ( 4 ) ;
user . MobileNo = dr . GetString ( 5 ) ;
user . EmailAddress = dr . GetString ( 6 ) ;
user . AuthKey = dr . GetString ( 7 ) ;
user . AuthValue = dr . GetString ( 8 ) ;
user . IsLocked = dr . GetBoolean ( 9 ) ;
user . LoginStatus = EnumLoginStatus . Success ;
user . UserRoleType = ( UserRoleTypeEnum ) dr . GetInt32 ( 10 ) ;
user . EmployeeNumber = dr . GetString ( 11 ) ;
user . DesignationCode = dr . GetString ( 12 ) ;
user . DesignationName = dr . GetString ( 13 ) ;
}
;
}
dr . Close ( ) ;
}
if ( user is null )
{
tc . End ( ) ;
throw new InvalidOperationException ( $"User not found with login: {request.LoginId}" ) ;
}
#endregion
#region If login successful and user is active read module id for this user
if ( user . LoginStatus = = EnumLoginStatus . Success & & user . Status = = EnumStatus . Authorized & & ! user . IsLocked )
{
p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . VarChar , pValue : user . LoginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginTime" , pType : SqlDbType . DateTime , pValue : null ) ,
SqlHelperExtension . CreateInParam ( pName : "@LogoutTime" , pType : SqlDbType . DateTime , pValue : DateTime . Now )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.SaveAccessLog" , parameterValues : p ) ;
}
#endregion
await _refreshTokenService . InvalidRefreshTokenAsync ( tc , user . UserId ) ;
response = new ( )
{
UserId = user . UserId ,
LoginId = user . LoginId ,
IsSuccess = true
} ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
public async Task < AppChangePasswordResponse > ChangePasswordAsync ( AppUserChangePasswordRequest request , string ipAddress )
{
AppChangePasswordResponse response = null ;
try
{
string password = EncryptPassword ( password : request . Password ) ;
User user = null ;
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
DateTime sysDate = DateTime . Today . Date ;
string appVer = string . Empty , alParams = string . Empty ;
#region Read User data using authentication data
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@LoginId" , pType : SqlDbType . NVarChar , pValue : request . LoginId )
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetUserByLogin" , parameterValues : p ) )
{
if ( dr . Read ( ) )
{
user = new User ( ) ;
{
user . UserId = dr . GetInt32 ( 0 ) ;
user . Password = dr . GetString ( 1 ) ;
user . LoginId = dr . GetString ( 2 ) ;
user . UserName = dr . GetString ( 3 ) ;
user . Status = ( EnumStatus ) dr . GetInt32 ( 4 ) ;
user . MobileNo = dr . GetString ( 5 ) ;
user . EmailAddress = dr . GetString ( 6 ) ;
user . AuthKey = dr . GetString ( 7 ) ;
user . AuthValue = dr . GetString ( 8 ) ;
user . IsLocked = dr . GetBoolean ( 9 ) ;
user . LoginStatus = EnumLoginStatus . Success ;
user . UserRoleType = ( UserRoleTypeEnum ) dr . GetInt32 ( 10 ) ;
user . EmployeeNumber = dr . GetString ( 11 ) ;
user . DesignationCode = dr . GetString ( 12 ) ;
user . DesignationName = dr . GetString ( 13 ) ;
}
;
}
dr . Close ( ) ;
}
if ( user is null )
{
tc . End ( ) ;
throw new InvalidOperationException ( $"User not found with login: {request.LoginId}" ) ;
}
if ( ! password . Equals ( user . Password ) )
{
tc . End ( ) ;
throw new InvalidOperationException ( $"Password mismatch for login: {request.LoginId}" ) ;
}
#endregion
string newPassword = EncryptPassword ( request . ConfirmPassword ) ;
p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : user . UserId ) ,
2026-07-06 18:20:41 +06:00
SqlHelperExtension . CreateInParam ( pName : "@Password" , pType : SqlDbType . NVarChar , pValue : newPassword , size : 50 ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastPassword" , pType : SqlDbType . NVarChar , pValue : password , size : 50 ) ,
2026-07-06 17:23:05 +06:00
SqlHelperExtension . CreateInParam ( pName : "@LastPasswordChnageDate" , pType : SqlDbType . DateTime , pValue : DateTime . Now )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.ChangePassword" , parameterValues : p ) ;
response = new ( )
{
UserId = user . UserId ,
LoginId = user . LoginId ,
IsSuccess = true
} ;
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
2026-06-15 18:26:58 +06:00
/// <summary>
///
/// </summary>
/// <param name="accessType"></param>
/// <param name="loginId"></param>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task < AccessLogResponse > GetAccessLogAsync ( int accessType , string loginId , DateTime startDate , DateTime endDate )
{
AccessLogResponse response = new ( ) { Value = [ ] } ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@AccessType" , pType : SqlDbType . SmallInt , pValue : accessType ) ,
SqlHelperExtension . CreateInParam ( pName : "@LoginID" , pType : SqlDbType . VarChar , pValue : loginId , size : 30 ) ,
SqlHelperExtension . CreateInParam ( pName : "@StartDate" , pType : SqlDbType . DateTime , pValue : startDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@EndDate" , pType : SqlDbType . DateTime , pValue : endDate ) ,
] ;
using IDataReader dr = tc . ExecuteReaderSp ( spName : "dbo.GetAccessLogData" , parameterValues : p ) ;
while ( dr . Read ( ) )
{
AccessLog item = new ( )
{
LoginId = dr . GetString ( 0 ) ,
LoginTime = dr . GetDateTime ( 1 ) ,
LoginIp = dr . GetString ( 2 ) ,
LogoutTime = dr . IsDBNull ( 3 ) ? null : dr . GetDateTime ( 3 ) ,
LogoutIp = dr . IsDBNull ( 4 ) ? null : dr . GetString ( 4 )
} ;
response . Value . Add ( item ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
/// <summary>
///
/// </summary>
/// <param name="maxAuthLimit"></param>
/// <param name="userId"></param>
/// <param name="ipAddress"></param>
/// <param name="savedBy"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task < bool > SaveAuthorizeLimitAsync ( decimal maxAuthLimit , int userId , string ipAddress , string savedBy )
{
bool returnValue ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@MaxAuthLimit" , pType : SqlDbType . Decimal , pValue : maxAuthLimit ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateInParam ( pName : "@IpAddress" , pType : SqlDbType . VarChar , pValue : ipAddress , size : 20 ) ,
SqlHelperExtension . CreateInParam ( pName : "@SavedBy" , pType : SqlDbType . VarChar , pValue : savedBy , size : 30 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.SaveAuthorizeLimit" , parameterValues : p ) ;
tc . End ( ) ;
returnValue = true ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return returnValue ;
}
public async Task < UserAuthorizeLimitResponse > GetAuthorizeLimitAsync ( int userId )
{
UserAuthorizeLimitResponse response = new ( ) { Value = 0 } ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
using IDataReader dr = tc . ExecuteReader ( commandText : "SELECT LoginId, MaxAuthLimit FROM dbo.Users WHERE UserId=%n" , args : userId ) ;
if ( dr . Read ( ) )
{
response . LoginId = dr . GetString ( 0 ) ;
response . Value = dr . IsDBNull ( 1 ) ? 0 : dr . GetDecimal ( 1 ) ;
}
dr . Close ( ) ;
tc . End ( ) ;
response . ReturnStatus = 200 ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
return response ;
}
#region Private functions
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="loginId"></param>
/// <param name="enfStgPwd"></param>
/// <param name="minLen"></param>
/// <param name="maxLen"></param>
/// <param name="reservedWords"></param>
/// <exception cref="Exception"></exception>
private void ReadPwdParams ( int userId , string loginId , out bool enfStgPwd , out short minLen , out short maxLen , out string reservedWords )
{
try
{
enfStgPwd = false ;
minLen = maxLen = 0 ;
reservedWords = string . Empty ;
using TransactionContext tc = TransactionContext . Begin ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
bool loginIdCantPwd = false ;
using ( IDataReader dr = tc . ExecuteReader ( "SELECT EnfStgPwd, PwdMinLen, PwdMaxLen, PwdRsvdWords, LoginIdCantPwd FROM ThisSystem" ) )
{
if ( dr . Read ( ) )
{
enfStgPwd = Convert . ToBoolean ( dr . GetInt16 ( 0 ) ) ;
minLen = dr . GetInt16 ( 1 ) ;
maxLen = dr . GetInt16 ( 2 ) ;
reservedWords = dr . IsDBNull ( 3 ) ? string . Empty : dr . GetString ( 3 ) ;
loginIdCantPwd = ! dr . IsDBNull ( 4 ) & & dr . GetInt16 ( 4 ) ! = 0 ;
}
dr . Close ( ) ;
}
if ( string . IsNullOrEmpty ( loginId ) & & loginIdCantPwd & & userId > 0 )
{
using IDataReader dr = tc . ExecuteReader ( "SELECT LoginId FROM Users WHERE UserId=%n" , userId ) ;
if ( dr . Read ( ) )
{
loginId = dr . IsDBNull ( 0 ) ? string . Empty : dr . GetString ( 0 ) ;
}
dr . Close ( ) ;
}
tc . End ( ) ;
if ( loginIdCantPwd & & ! string . IsNullOrEmpty ( loginId ) )
{
reservedWords = string . IsNullOrEmpty ( reservedWords ) ? loginId : $"{reservedWords},{loginId}" ;
}
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
///
/// </summary>
/// <param name="password"></param>
/// <param name="minLen"></param>
/// <param name="maxLen"></param>
/// <param name="enfStgPwd"></param>
/// <param name="reservedWords"></param>
/// <param name="daLastPwds"></param>
/// <param name="pwdHistories"></param>
/// <param name="actPwdHistories"></param>
/// <exception cref="Exception"></exception>
private void CheckPasswordHistory ( string password , short minLen , short maxLen , bool enfStgPwd , string reservedWords , int daLastPwds , Queue < string > pwdHistories , List < string > actPwdHistories )
{
try
{
ValidatePwdPolicies ( password : password , minLen : minLen , maxLen : maxLen , enfStgPwd : enfStgPwd , reservedWords : reservedWords ) ;
password = EncryptPassword ( password : password ) ;
if ( daLastPwds > 0 & & actPwdHistories . Contains ( password ) )
throw new InvalidOperationException ( $"You cannot use this password, because it was used in last {daLastPwds} passwords." ) ;
if ( pwdHistories . Count > = 5 )
pwdHistories . Dequeue ( ) ;
pwdHistories . Enqueue ( password ) ;
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
/// Validates a password against specified policies, including length constraints, reserved words, and strong password requirements.
/// </summary>
/// <remarks>This method performs validation based on the provided policies and throws an exception if the password does not comply.
/// Ensure that all parameters are correctly configured before calling this method.</remarks>
/// <param name="password">The password to validate. Cannot be null or empty.</param>
/// <param name="minLen">The minimum allowed length for the password. Must be greater than 0.</param>
/// <param name="maxLen">The maximum allowed length for the password. Must be greater than 0.</param>
/// <param name="enfStgPwd">A value indicating whether strong password enforcement is enabled. If <see langword="true"/>, the password
/// must contain at least one uppercase letter, one lowercase letter, one number, and one special character (!, @, #, $, %, ^, &, *, ?).</param>
/// <param name="reservedWords">A comma-separated list of reserved words that cannot be included in the password. Cannot be null or empty.</param>
/// <exception cref="InvalidOperationException">Thrown if the password violates any of the specified policies, including: <list type="bullet">
/// <item><description>Contains a reserved word.</description></item> <item><description>Does not meet the minimum length requirement.</description></item> <item>
/// <description>Exceeds the maximum length requirement.</description></item> <item><description>Fails strong password enforcement when <paramref
/// name="enfStgPwd"/> is <see langword="true"/>.</description></item> </list></exception>
private static void ValidatePwdPolicies ( string password , short minLen , short maxLen , bool enfStgPwd , string reservedWords )
{
try
{
if ( ! string . IsNullOrEmpty ( password ) & & ! string . IsNullOrEmpty ( reservedWords ) )
{
List < string > words = [ . . reservedWords . Split ( ',' ) ] ;
foreach ( string word in words )
{
if ( password . Contains ( word , StringComparison . InvariantCultureIgnoreCase ) )
throw new InvalidOperationException ( $"[{word}] can not be used in password." ) ;
}
}
if ( minLen > 0 & & password . Length < minLen )
throw new InvalidOperationException ( $"Minimum length of Password is {minLen}" ) ;
if ( maxLen > 0 & & password . Length > maxLen )
throw new InvalidOperationException ( $"Maximum length of Password is {maxLen}" ) ;
if ( enfStgPwd & & ! Global . StringFunctions . IsStrongPassword ( password ) )
throw new InvalidOperationException ( "Must have Upper & Lower case character, a Number and a Special character (!, @, #, $, %, ^, &, *, ?)." ) ;
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
///
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
private string EncryptPassword ( string password )
{
try
{
string pwdSecretKey = GlobalFunctions . ConvertFromBase64String ( _settings . PwdSecretKey ) ;
return Global . CipherFunctions . EncryptByAES ( privateKey : pwdSecretKey , publicKey : pwdSecretKey , data : password ) ;
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
///
/// </summary>
/// <param name="tc"></param>
/// <param name="authValue"></param>
/// <param name="validMinutes"></param>
/// <param name="userId"></param>
private static void SetAuthValue ( TransactionContext tc , string authValue , int validMinutes , int userId )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@AuthValue" , pType : SqlDbType . VarChar , pValue : authValue , size : 10 ) ,
SqlHelperExtension . CreateInParam ( pName : "@ValidMinutes" , pType : SqlDbType . Int , pValue : validMinutes ) ,
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.SetAuthValue" , parameterValues : p ) ;
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
///
/// </summary>
/// <param name="tc"></param>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
private static int GetPendingNotifCount ( TransactionContext tc , int userId )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
SqlHelperExtension . CreateOutParam ( pName : "@NotifCount" , pType : SqlDbType . Int , pValue : 0 )
] ;
_ = tc . ExecuteNonQuerySp ( spName : "dbo.GetPendingAuthCountByUser" , parameterValues : p ) ;
return ( p [ 1 ] . Value ! = null & & p [ 1 ] . Value ! = DBNull . Value ) ? Convert . ToInt32 ( p [ 1 ] . Value ) : 0 ;
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
///
/// </summary>
/// <param name="parent"></param>
/// <param name="data"></param>
/// <param name="pmns"></param>
private static void MakeHierarchy ( GroupPermission parent , List < GroupPermission > data , List < GroupPermission > pmns )
{
try
{
IEnumerable < GroupPermission > children = data . Where ( x = > x . ParentId = = parent . ModuleId & & x . Visible & & pmns . Where ( y = > y . AllowSelect ) . Select ( z = > z . ModuleId ) . Contains ( x . ModuleId ) ) ;
parent . Children . AddRange ( children ) ;
foreach ( GroupPermission child in parent . Children )
{
MakeHierarchy ( parent : child , data : data , pmns : pmns ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
/// <summary>
///
/// </summary>
/// <param name="src"></param>
/// <param name="dst"></param>
private void CopyHierarchy ( GroupPermission src , MenuItem dst )
{
try
{
if ( src . Children ? . Count > 0 )
dst . Items = [ ] ;
foreach ( GroupPermission srcChild in src . Children )
{
MenuItem dstChild = srcChild . Copy ( ) ;
dstChild . Label = _menuSettings ? . GetItem ( dstChild . ModuleId , dstChild . Label ) . Value ;
dst . Items . Add ( dstChild ) ;
CopyHierarchy ( src : srcChild , dst : dstChild ) ;
}
}
catch ( Exception e )
{
throw new InvalidOperationException ( e . Message , e ) ;
}
}
2026-06-14 12:46:29 +06:00
public Task < bool > SaveAttributesAsync ( int userId , int clientType , string ipAddress , int attributeSetBy , List < string > ukIds )
{
throw new NotImplementedException ( ) ;
}
2026-07-06 17:23:05 +06:00
2026-06-14 12:46:29 +06:00
#endregion
}
}