Update
This commit is contained in:
parent
3610536233
commit
a1e2bf6ae0
@ -21,13 +21,15 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
private readonly IdentityDBContext _identityDbContext;
|
private readonly IdentityDBContext _identityDbContext;
|
||||||
private readonly UserManager<UserModel> _userManager;
|
private readonly UserManager<UserModel> _userManager;
|
||||||
private readonly SignInManager<UserModel> _signInManager;
|
private readonly SignInManager<UserModel> _signInManager;
|
||||||
|
private readonly RoleManager<RoleModel> _roleManager;
|
||||||
|
|
||||||
public AdminAPI(ILogger<AdminAPI> logger, IdentityDBContext authDbContext, UserManager<UserModel> userManager, SignInManager<UserModel> signInManager)
|
public AdminAPI(ILogger<AdminAPI> logger, IdentityDBContext authDbContext, UserManager<UserModel> userManager, SignInManager<UserModel> signInManager, RoleManager<RoleModel> roleManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_identityDbContext = authDbContext;
|
_identityDbContext = authDbContext;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
|
_roleManager = roleManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("GetClassAndMethodInformation")]
|
[HttpPost("GetClassAndMethodInformation")]
|
||||||
@ -86,6 +88,7 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
// Return the list as JSON
|
// Return the list as JSON
|
||||||
return Json(controllerAndMethodList);
|
return Json(controllerAndMethodList);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("GetUserList")]
|
[HttpPost("GetUserList")]
|
||||||
public async Task<IActionResult> GetUserList()
|
public async Task<IActionResult> GetUserList()
|
||||||
{
|
{
|
||||||
@ -98,7 +101,7 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
|
|
||||||
// Fetch all users excluding those with roles SuperAdmin or SystemAdmin
|
// Fetch all users excluding those with roles SuperAdmin or SystemAdmin
|
||||||
var allUsers = await _identityDbContext.Users
|
var allUsers = await _identityDbContext.Users
|
||||||
.Include(u => u.Department)
|
.Include(u => u.Department.Company)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (userRole == null || userRole.Count == 0)
|
if (userRole == null || userRole.Count == 0)
|
||||||
@ -113,16 +116,17 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
userInfo = await _identityDbContext.Users.Include(u => u.Department).ToListAsync();
|
userInfo = allUsers;
|
||||||
}
|
}
|
||||||
var userList = userInfo.Select(u => new
|
var userList = userInfo.Select(u => new
|
||||||
{
|
{
|
||||||
id = u.Id,
|
id = u.Id,
|
||||||
email = u.NormalizedEmail,
|
email = u.NormalizedEmail,
|
||||||
company = u.Department?.Company?.CompanyName,
|
company = u.Department?.Company?.CompanyName,
|
||||||
department = u.Department,
|
department = u.Department?.DepartmentName,
|
||||||
role = _userManager.GetRolesAsync(u).Result
|
role = _userManager.GetRolesAsync(u).Result,
|
||||||
|
status = u.UserInfoStatus,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
return Ok(new { UserInfo = userList });
|
return Ok(new { UserInfo = userList });
|
||||||
}
|
}
|
||||||
@ -132,6 +136,43 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPatch("UpdateUserStatusAndRole/{id}")]
|
||||||
|
public async Task<IActionResult> UpdateUserStatusAndRole(int id, [FromBody] string role)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _identityDbContext.Users.FindAsync(id);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound(new { message = "User not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var existingUserRoles = await _userManager.GetRolesAsync(user);
|
||||||
|
if (existingUserRoles != null && existingUserRoles.Count > 0) {
|
||||||
|
await _userManager.RemoveFromRolesAsync(user, existingUserRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _userManager.AddToRoleAsync(user, role);
|
||||||
|
|
||||||
|
user.UserInfoStatus = 1;
|
||||||
|
await _identityDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Ok(new { message = "User updated successfully" });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return StatusCode(500, $"An error occurred: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("GetRoleList")]
|
||||||
|
public async Task<IActionResult> GetRoleList()
|
||||||
|
{
|
||||||
|
var roles = await _roleManager.Roles.Select(r => new { r.Id, r.Name }).Where(r => r.Name != "SuperAdmin" && r.Name != "SystemAdmin").ToListAsync();
|
||||||
|
return Json(roles);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("GetDepartmentWithCompanyList")]
|
[HttpPost("GetDepartmentWithCompanyList")]
|
||||||
public async Task<IActionResult> GetDepartmentWithCompanyList()
|
public async Task<IActionResult> GetDepartmentWithCompanyList()
|
||||||
{
|
{
|
||||||
@ -160,12 +201,13 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
DepartmentId = departmentList!.DepartmentId,
|
DepartmentId = departmentList!.DepartmentId,
|
||||||
DepartmentName = departmentList.DepartmentName,
|
DepartmentName = departmentList.DepartmentName,
|
||||||
CompanyId = departmentList.CompanyId,
|
CompanyId = departmentList.CompanyId,
|
||||||
CompanyName = companyList?.CompanyName
|
CompanyName = companyList?.CompanyName,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the constructed list as JSON
|
// Return the constructed list as JSON
|
||||||
return departmentWithCompany;
|
return departmentWithCompany;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("AddCompanyDepartment")]
|
[HttpPost("AddCompanyDepartment")]
|
||||||
public async Task<IActionResult> AddCompanyDepartment([FromBody] UpdateDepartmentCompany departmentCompanyDetails)
|
public async Task<IActionResult> AddCompanyDepartment([FromBody] UpdateDepartmentCompany departmentCompanyDetails)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -62,11 +62,6 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
return StatusCode(500, $"An error occurred: {ex.Message}");
|
return StatusCode(500, $"An error occurred: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class LdapLoginCredential
|
|
||||||
{
|
|
||||||
public required string username { get; set; }
|
|
||||||
public required string password { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("LdapLogin")]
|
[HttpPost("LdapLogin")]
|
||||||
public async Task<IActionResult> LdapLogin([FromBody] LdapLoginCredential ldapLoginInfo)
|
public async Task<IActionResult> LdapLogin([FromBody] LdapLoginCredential ldapLoginInfo)
|
||||||
@ -140,7 +135,7 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
|
|
||||||
await _signInManager.SignInAsync(existUser, false);
|
await _signInManager.SignInAsync(existUser, false);
|
||||||
|
|
||||||
if (existUser.UserStatus == null || existUser.UserStatus != 0)
|
if (existUser.UserInfoStatus == null || existUser.UserInfoStatus != 0)
|
||||||
{
|
{
|
||||||
return Ok(new { RedirectUrl = Url.Action("ComDeptAssignment", "Identity") });
|
return Ok(new { RedirectUrl = Url.Action("ComDeptAssignment", "Identity") });
|
||||||
}
|
}
|
||||||
@ -190,10 +185,23 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
|
|
||||||
#endregion Department
|
#endregion Department
|
||||||
|
|
||||||
[HttpPost("UserComptDeptAssignment")]
|
[HttpPost("UserComptDeptAssignment/{id}")]
|
||||||
public async Task<IActionResult> UserComptDeptAssignment([FromBody] UserModel userModel)
|
public async Task<IActionResult> UserComptDeptAssignment([FromBody] UserDeptAssignment userDeptAssignment, int id)
|
||||||
{
|
{
|
||||||
return Ok();
|
var deptId = userDeptAssignment.departmentId;
|
||||||
|
if (deptId <= 0)
|
||||||
|
{
|
||||||
|
return BadRequest(new { message = "Invalid department ID provided." });
|
||||||
|
}
|
||||||
|
var user = await _userManager.FindByIdAsync(id.ToString());
|
||||||
|
if(user == null)
|
||||||
|
{
|
||||||
|
return NotFound( new { message = $"Unable to load user with ID '{id}'." });
|
||||||
|
}
|
||||||
|
user.UserInfoStatus = 0;
|
||||||
|
user.departmentId = deptId;
|
||||||
|
await _userManager.UpdateAsync(user);
|
||||||
|
return Ok( new { message = "User updated successfully", RedirectUrl = Url.Action("Index", "Home") });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserModel?> doUserExists(string username)
|
public async Task<UserModel?> doUserExists(string username)
|
||||||
@ -202,6 +210,15 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
return user != null ? user : null;
|
return user != null ? user : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LdapLoginCredential
|
||||||
|
{
|
||||||
|
public required string username { get; set; }
|
||||||
|
public required string password { get; set; }
|
||||||
|
}
|
||||||
|
public class UserDeptAssignment()
|
||||||
|
{
|
||||||
|
public required int departmentId { get; set; }
|
||||||
|
}
|
||||||
class userLdapInfo()
|
class userLdapInfo()
|
||||||
{
|
{
|
||||||
public required bool Authenticated { get; set; }
|
public required bool Authenticated { get; set; }
|
||||||
|
|||||||
@ -52,7 +52,7 @@ namespace PSTW_CentralSystem.DBContext
|
|||||||
NormalizedEmail = "ADMIN@PSTW.COM.MY",
|
NormalizedEmail = "ADMIN@PSTW.COM.MY",
|
||||||
SecurityStamp = Guid.NewGuid().ToString(),
|
SecurityStamp = Guid.NewGuid().ToString(),
|
||||||
EmailConfirmed = true,
|
EmailConfirmed = true,
|
||||||
UserStatus = 1,
|
UserInfoStatus = 1,
|
||||||
};
|
};
|
||||||
var systemAdmin = new UserModel
|
var systemAdmin = new UserModel
|
||||||
{
|
{
|
||||||
@ -64,7 +64,7 @@ namespace PSTW_CentralSystem.DBContext
|
|||||||
NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
|
NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
|
||||||
SecurityStamp = Guid.NewGuid().ToString(),
|
SecurityStamp = Guid.NewGuid().ToString(),
|
||||||
EmailConfirmed = true,
|
EmailConfirmed = true,
|
||||||
UserStatus = 1,
|
UserInfoStatus = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hash the password
|
// Hash the password
|
||||||
|
|||||||
@ -12,7 +12,7 @@ using PSTW_CentralSystem.DBContext;
|
|||||||
namespace PSTW_CentralSystem.Migrations
|
namespace PSTW_CentralSystem.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(IdentityDBContext))]
|
[DbContext(typeof(IdentityDBContext))]
|
||||||
[Migration("20241206015840_Initiate")]
|
[Migration("20241218060528_Initiate")]
|
||||||
partial class Initiate
|
partial class Initiate
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -329,13 +329,13 @@ namespace PSTW_CentralSystem.Migrations
|
|||||||
b.Property<bool>("TwoFactorEnabled")
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int?>("UserInfoStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
b.Property<string>("UserName")
|
||||||
.HasMaxLength(256)
|
.HasMaxLength(256)
|
||||||
.HasColumnType("varchar(256)");
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
b.Property<int?>("UserStatus")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<int?>("departmentId")
|
b.Property<int?>("departmentId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
@ -357,34 +357,36 @@ namespace PSTW_CentralSystem.Migrations
|
|||||||
{
|
{
|
||||||
Id = 1,
|
Id = 1,
|
||||||
AccessFailedCount = 0,
|
AccessFailedCount = 0,
|
||||||
ConcurrencyStamp = "b58597b6-2835-4ff6-b437-11ec7a213434",
|
ConcurrencyStamp = "f89f9499-14a5-4bba-a003-5bbb0ef1bb12",
|
||||||
Email = "admin@pstw.com.my",
|
Email = "admin@pstw.com.my",
|
||||||
EmailConfirmed = true,
|
EmailConfirmed = true,
|
||||||
FullName = "MAAdmin",
|
FullName = "MAAdmin",
|
||||||
LockoutEnabled = false,
|
LockoutEnabled = false,
|
||||||
NormalizedEmail = "ADMIN@PSTW.COM.MY",
|
NormalizedEmail = "ADMIN@PSTW.COM.MY",
|
||||||
NormalizedUserName = "ADMIN@PSTW.COM.MY",
|
NormalizedUserName = "ADMIN@PSTW.COM.MY",
|
||||||
PasswordHash = "AQAAAAIAAYagAAAAECA03al9kGFTKlmmTls3wiH4NV7HlL76680Qx6lR7d77LHJwIN6/Wt1MBCP9TE1qfg==",
|
PasswordHash = "AQAAAAIAAYagAAAAEDue4k8/8FwBvdJbbgBDLH+ibzmThXls6CmbJd99AdlrbPZrOWvWxlkv7cwVsPSM9g==",
|
||||||
PhoneNumberConfirmed = false,
|
PhoneNumberConfirmed = false,
|
||||||
SecurityStamp = "0f649a27-6566-436c-bc27-d1a6b8e7f846",
|
SecurityStamp = "d5684375-c368-409a-82e1-1e44fa05de60",
|
||||||
TwoFactorEnabled = false,
|
TwoFactorEnabled = false,
|
||||||
|
UserInfoStatus = 1,
|
||||||
UserName = "admin@pstw.com.my"
|
UserName = "admin@pstw.com.my"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 2,
|
Id = 2,
|
||||||
AccessFailedCount = 0,
|
AccessFailedCount = 0,
|
||||||
ConcurrencyStamp = "cf9424fc-8afc-4f59-a0a6-34574676273c",
|
ConcurrencyStamp = "d19f378c-eef5-4cf7-8ec6-c6b3904e4749",
|
||||||
Email = "sysadmin@pstw.com.my",
|
Email = "sysadmin@pstw.com.my",
|
||||||
EmailConfirmed = true,
|
EmailConfirmed = true,
|
||||||
FullName = "SysAdmin",
|
FullName = "SysAdmin",
|
||||||
LockoutEnabled = false,
|
LockoutEnabled = false,
|
||||||
NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
|
NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
|
||||||
NormalizedUserName = "SYSADMIN@PSTW.COM.MY",
|
NormalizedUserName = "SYSADMIN@PSTW.COM.MY",
|
||||||
PasswordHash = "AQAAAAIAAYagAAAAEMkwXv250FjOjdLEAY2a/aEF3g3iu9xCVORV/MH37kVcj8vgJez+LlfJtjklaschLg==",
|
PasswordHash = "AQAAAAIAAYagAAAAEDme/kiOHre+s0r9XvpwSr5dZIoWIbSJhI5B19mCjH4ZFoBBlF6Pay9WYJ2jcVZgfw==",
|
||||||
PhoneNumberConfirmed = false,
|
PhoneNumberConfirmed = false,
|
||||||
SecurityStamp = "8efe9683-78fb-404d-96a9-b8b7302c03b2",
|
SecurityStamp = "7875eac4-323d-43cb-a083-940e52877171",
|
||||||
TwoFactorEnabled = false,
|
TwoFactorEnabled = false,
|
||||||
|
UserInfoStatus = 1,
|
||||||
UserName = "sysadmin@pstw.com.my"
|
UserName = "sysadmin@pstw.com.my"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -131,7 +131,7 @@ namespace PSTW_CentralSystem.Migrations
|
|||||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
FullName = table.Column<string>(type: "longtext", nullable: true)
|
FullName = table.Column<string>(type: "longtext", nullable: true)
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
UserStatus = table.Column<int>(type: "int", nullable: true),
|
UserInfoStatus = table.Column<int>(type: "int", nullable: true),
|
||||||
departmentId = table.Column<int>(type: "int", nullable: true),
|
departmentId = table.Column<int>(type: "int", nullable: true),
|
||||||
UserName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
UserName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
@ -277,11 +277,11 @@ namespace PSTW_CentralSystem.Migrations
|
|||||||
|
|
||||||
migrationBuilder.InsertData(
|
migrationBuilder.InsertData(
|
||||||
table: "AspNetUsers",
|
table: "AspNetUsers",
|
||||||
columns: new[] { "Id", "AccessFailedCount", "ConcurrencyStamp", "Email", "EmailConfirmed", "FullName", "LockoutEnabled", "LockoutEnd", "NormalizedEmail", "NormalizedUserName", "PasswordHash", "PhoneNumber", "PhoneNumberConfirmed", "SecurityStamp", "TwoFactorEnabled", "UserName", "UserStatus", "departmentId" },
|
columns: new[] { "Id", "AccessFailedCount", "ConcurrencyStamp", "Email", "EmailConfirmed", "FullName", "LockoutEnabled", "LockoutEnd", "NormalizedEmail", "NormalizedUserName", "PasswordHash", "PhoneNumber", "PhoneNumberConfirmed", "SecurityStamp", "TwoFactorEnabled", "UserInfoStatus", "UserName", "departmentId" },
|
||||||
values: new object[,]
|
values: new object[,]
|
||||||
{
|
{
|
||||||
{ 1, 0, "b58597b6-2835-4ff6-b437-11ec7a213434", "admin@pstw.com.my", true, "MAAdmin", false, null, "ADMIN@PSTW.COM.MY", "ADMIN@PSTW.COM.MY", "AQAAAAIAAYagAAAAECA03al9kGFTKlmmTls3wiH4NV7HlL76680Qx6lR7d77LHJwIN6/Wt1MBCP9TE1qfg==", null, false, "0f649a27-6566-436c-bc27-d1a6b8e7f846", false, "admin@pstw.com.my", null, null },
|
{ 1, 0, "f89f9499-14a5-4bba-a003-5bbb0ef1bb12", "admin@pstw.com.my", true, "MAAdmin", false, null, "ADMIN@PSTW.COM.MY", "ADMIN@PSTW.COM.MY", "AQAAAAIAAYagAAAAEDue4k8/8FwBvdJbbgBDLH+ibzmThXls6CmbJd99AdlrbPZrOWvWxlkv7cwVsPSM9g==", null, false, "d5684375-c368-409a-82e1-1e44fa05de60", false, 1, "admin@pstw.com.my", null },
|
||||||
{ 2, 0, "cf9424fc-8afc-4f59-a0a6-34574676273c", "sysadmin@pstw.com.my", true, "SysAdmin", false, null, "SYSADMIN@PSTW.COM.MY", "SYSADMIN@PSTW.COM.MY", "AQAAAAIAAYagAAAAEMkwXv250FjOjdLEAY2a/aEF3g3iu9xCVORV/MH37kVcj8vgJez+LlfJtjklaschLg==", null, false, "8efe9683-78fb-404d-96a9-b8b7302c03b2", false, "sysadmin@pstw.com.my", null, null }
|
{ 2, 0, "d19f378c-eef5-4cf7-8ec6-c6b3904e4749", "sysadmin@pstw.com.my", true, "SysAdmin", false, null, "SYSADMIN@PSTW.COM.MY", "SYSADMIN@PSTW.COM.MY", "AQAAAAIAAYagAAAAEDme/kiOHre+s0r9XvpwSr5dZIoWIbSJhI5B19mCjH4ZFoBBlF6Pay9WYJ2jcVZgfw==", null, false, "7875eac4-323d-43cb-a083-940e52877171", false, 1, "sysadmin@pstw.com.my", null }
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.InsertData(
|
migrationBuilder.InsertData(
|
||||||
@ -326,13 +326,13 @@ namespace PSTW_CentralSystem.Migrations
|
|||||||
b.Property<bool>("TwoFactorEnabled")
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<int?>("UserInfoStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
b.Property<string>("UserName")
|
||||||
.HasMaxLength(256)
|
.HasMaxLength(256)
|
||||||
.HasColumnType("varchar(256)");
|
.HasColumnType("varchar(256)");
|
||||||
|
|
||||||
b.Property<int?>("UserStatus")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<int?>("departmentId")
|
b.Property<int?>("departmentId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
@ -354,34 +354,36 @@ namespace PSTW_CentralSystem.Migrations
|
|||||||
{
|
{
|
||||||
Id = 1,
|
Id = 1,
|
||||||
AccessFailedCount = 0,
|
AccessFailedCount = 0,
|
||||||
ConcurrencyStamp = "b58597b6-2835-4ff6-b437-11ec7a213434",
|
ConcurrencyStamp = "f89f9499-14a5-4bba-a003-5bbb0ef1bb12",
|
||||||
Email = "admin@pstw.com.my",
|
Email = "admin@pstw.com.my",
|
||||||
EmailConfirmed = true,
|
EmailConfirmed = true,
|
||||||
FullName = "MAAdmin",
|
FullName = "MAAdmin",
|
||||||
LockoutEnabled = false,
|
LockoutEnabled = false,
|
||||||
NormalizedEmail = "ADMIN@PSTW.COM.MY",
|
NormalizedEmail = "ADMIN@PSTW.COM.MY",
|
||||||
NormalizedUserName = "ADMIN@PSTW.COM.MY",
|
NormalizedUserName = "ADMIN@PSTW.COM.MY",
|
||||||
PasswordHash = "AQAAAAIAAYagAAAAECA03al9kGFTKlmmTls3wiH4NV7HlL76680Qx6lR7d77LHJwIN6/Wt1MBCP9TE1qfg==",
|
PasswordHash = "AQAAAAIAAYagAAAAEDue4k8/8FwBvdJbbgBDLH+ibzmThXls6CmbJd99AdlrbPZrOWvWxlkv7cwVsPSM9g==",
|
||||||
PhoneNumberConfirmed = false,
|
PhoneNumberConfirmed = false,
|
||||||
SecurityStamp = "0f649a27-6566-436c-bc27-d1a6b8e7f846",
|
SecurityStamp = "d5684375-c368-409a-82e1-1e44fa05de60",
|
||||||
TwoFactorEnabled = false,
|
TwoFactorEnabled = false,
|
||||||
|
UserInfoStatus = 1,
|
||||||
UserName = "admin@pstw.com.my"
|
UserName = "admin@pstw.com.my"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 2,
|
Id = 2,
|
||||||
AccessFailedCount = 0,
|
AccessFailedCount = 0,
|
||||||
ConcurrencyStamp = "cf9424fc-8afc-4f59-a0a6-34574676273c",
|
ConcurrencyStamp = "d19f378c-eef5-4cf7-8ec6-c6b3904e4749",
|
||||||
Email = "sysadmin@pstw.com.my",
|
Email = "sysadmin@pstw.com.my",
|
||||||
EmailConfirmed = true,
|
EmailConfirmed = true,
|
||||||
FullName = "SysAdmin",
|
FullName = "SysAdmin",
|
||||||
LockoutEnabled = false,
|
LockoutEnabled = false,
|
||||||
NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
|
NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
|
||||||
NormalizedUserName = "SYSADMIN@PSTW.COM.MY",
|
NormalizedUserName = "SYSADMIN@PSTW.COM.MY",
|
||||||
PasswordHash = "AQAAAAIAAYagAAAAEMkwXv250FjOjdLEAY2a/aEF3g3iu9xCVORV/MH37kVcj8vgJez+LlfJtjklaschLg==",
|
PasswordHash = "AQAAAAIAAYagAAAAEDme/kiOHre+s0r9XvpwSr5dZIoWIbSJhI5B19mCjH4ZFoBBlF6Pay9WYJ2jcVZgfw==",
|
||||||
PhoneNumberConfirmed = false,
|
PhoneNumberConfirmed = false,
|
||||||
SecurityStamp = "8efe9683-78fb-404d-96a9-b8b7302c03b2",
|
SecurityStamp = "7875eac4-323d-43cb-a083-940e52877171",
|
||||||
TwoFactorEnabled = false,
|
TwoFactorEnabled = false,
|
||||||
|
UserInfoStatus = 1,
|
||||||
UserName = "sysadmin@pstw.com.my"
|
UserName = "sysadmin@pstw.com.my"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -300,7 +300,7 @@ namespace PSTW_CentralSystem.Migrations.InventoryDB
|
|||||||
b.Property<string>("UserName")
|
b.Property<string>("UserName")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<int?>("UserStatus")
|
b.Property<int?>("UserInfoStatus")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int?>("departmentId")
|
b.Property<int?>("departmentId")
|
||||||
|
|||||||
@ -297,7 +297,7 @@ namespace PSTW_CentralSystem.Migrations.InventoryDB
|
|||||||
b.Property<string>("UserName")
|
b.Property<string>("UserName")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<int?>("UserStatus")
|
b.Property<int?>("UserInfoStatus")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int?>("departmentId")
|
b.Property<int?>("departmentId")
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace PSTW_CentralSystem.Models
|
|||||||
{
|
{
|
||||||
// Add custom properties
|
// Add custom properties
|
||||||
public string? FullName { get; set; }
|
public string? FullName { get; set; }
|
||||||
public int? UserStatus { get; set; }
|
public int? UserInfoStatus { get; set; }
|
||||||
public int? departmentId { get; set; }
|
public int? departmentId { get; set; }
|
||||||
[ForeignKey("departmentId")]
|
[ForeignKey("departmentId")]
|
||||||
public virtual DepartmentModel? Department { get; set; }
|
public virtual DepartmentModel? Department { get; set; }
|
||||||
|
|||||||
@ -150,6 +150,7 @@
|
|||||||
departmentName: '',
|
departmentName: '',
|
||||||
departmentCode: '',
|
departmentCode: '',
|
||||||
}],
|
}],
|
||||||
|
compDeptDatatable: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -173,6 +174,9 @@
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
this.compDeptList = data ? data : [];
|
this.compDeptList = data ? data : [];
|
||||||
|
if (this.compDeptDatatable != null) {
|
||||||
|
this.compDeptDatatable.clear().destroy();
|
||||||
|
}
|
||||||
this.initiateTable();
|
this.initiateTable();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@ -231,9 +235,14 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.itemDatatable = $('#userDatatable').DataTable({
|
this.compDeptDatatable = $('#userDatatable').DataTable({
|
||||||
"data": flatData,
|
"data": flatData,
|
||||||
"columns": [
|
"columns": [
|
||||||
|
{
|
||||||
|
"title": "Company Name",
|
||||||
|
"data": "companyName",
|
||||||
|
"visible": false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "Department Name",
|
"title": "Department Name",
|
||||||
"data": "departmentName",
|
"data": "departmentName",
|
||||||
@ -255,6 +264,7 @@
|
|||||||
"dataSrc": "companyName" // Group rows by the companyName column
|
"dataSrc": "companyName" // Group rows by the companyName column
|
||||||
},
|
},
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
ordering: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Attach click event listener to the delete buttons
|
// Attach click event listener to the delete buttons
|
||||||
@ -306,6 +316,9 @@
|
|||||||
alert(error.message);
|
alert(error.message);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
$('#loadingModal').on('shown.bs.modal', resolve);
|
||||||
|
});
|
||||||
$('#loadingModal').modal('hide');
|
$('#loadingModal').modal('hide');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -327,13 +340,10 @@
|
|||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
// Attach a click event listener to elements with the class 'btn-success'.
|
|
||||||
$('#addCompDeptBtn').on('click', function () {
|
$('#addCompDeptBtn').on('click', function () {
|
||||||
// Show the modal with the ID 'addManufacturerModal'.
|
|
||||||
$('#registerCompDept').modal('show');
|
$('#registerCompDept').modal('show');
|
||||||
});
|
});
|
||||||
$('.closeModal').on('click', function () {
|
$('.closeModal').on('click', function () {
|
||||||
// Show the modal with the ID 'addManufacturerModal'.
|
|
||||||
$('.modal').modal('hide');
|
$('.modal').modal('hide');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,10 +14,10 @@
|
|||||||
<div class="col-md-12 col-lg-12">
|
<div class="col-md-12 col-lg-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">Latest Posts</h4>
|
<h4 class="card-title">User List</h4>
|
||||||
<div class="col-md-12 col-lg-12">
|
<div class="col-md-12 col-lg-12">
|
||||||
<div>
|
<div>
|
||||||
<table class="table table-bordered table-hover table-striped no-wrap" id="userDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
|
<table class="table table-bordered table-hover table-striped no-wrap align-middle" id="userDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -54,25 +54,51 @@
|
|||||||
await Html.RenderPartialAsync("_ValidationScriptsPartial");
|
await Html.RenderPartialAsync("_ValidationScriptsPartial");
|
||||||
}
|
}
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
app.mount('#app');
|
||||||
|
});
|
||||||
|
|
||||||
const app = Vue.createApp({
|
const app = Vue.createApp({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userList: null,
|
userList: null,
|
||||||
selectedModule: null
|
roleList: null,
|
||||||
|
selectedModule: null,
|
||||||
|
selectedRole: [],
|
||||||
|
userDatatable: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchUsers();
|
this.fetchUsers();
|
||||||
|
this.fetchRoles();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetchUsers() {
|
async fetchUsers() {
|
||||||
fetch('/AdminAPI/GetUserList', {
|
fetch('/AdminAPI/GetUserList', {
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this.userList = data.userInfo.length ? data.userInfo : [];
|
this.userList = data.userInfo.length ? data.userInfo : [];
|
||||||
this.initiateTable();
|
this.$nextTick(() => {
|
||||||
|
if (this.userDatatable != null) {
|
||||||
|
this.userDatatable.clear().destroy();
|
||||||
|
}
|
||||||
|
this.initiateTable();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('There was a problem with the fetch operation:', error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async fetchRoles() {
|
||||||
|
fetch('/AdminAPI/GetRoleList', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
this.roleList = data.length ? data : [];
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('There was a problem with the fetch operation:', error);
|
console.error('There was a problem with the fetch operation:', error);
|
||||||
@ -116,20 +142,11 @@
|
|||||||
hideModal() {
|
hideModal() {
|
||||||
$('#confirm-dialog').modal('hide');
|
$('#confirm-dialog').modal('hide');
|
||||||
},
|
},
|
||||||
initiateTable() {
|
async initiateTable() {
|
||||||
self = this;
|
self = this;
|
||||||
console.log(self.userList)
|
this.userDatatable = $('#userDatatable').DataTable({
|
||||||
this.itemDatatable = $('#userDatatable').DataTable({
|
|
||||||
"data": self.userList,
|
"data": self.userList,
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
|
||||||
"title": "UID",
|
|
||||||
"data": "id",
|
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
|
||||||
// Assign a unique ID to the <td> element
|
|
||||||
$(td).attr('id', `qr${cellData}`);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "Email",
|
"title": "Email",
|
||||||
"data": "email",
|
"data": "email",
|
||||||
@ -145,6 +162,52 @@
|
|||||||
{
|
{
|
||||||
"title": "Role",
|
"title": "Role",
|
||||||
"data": "role",
|
"data": "role",
|
||||||
|
"render": function (data, type, row, meta) {
|
||||||
|
if (data.length > 0) {
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
var thisCol = `
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<select class="form-select role-select" data-id="${row.id}">
|
||||||
|
<option value="" selected disabled>Select Role</option>
|
||||||
|
${self.roleList && self.roleList.map(role => `<option value="${role.name}">${role.name}</option>`).join('')}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<button type="button" class="btn btn-primary update-btn" data-id="${row.id}">Update</button>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
return thisCol;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Info Status",
|
||||||
|
"data": "status",
|
||||||
|
"render": function (data, type, row, meta) {
|
||||||
|
return data == 1 ? `Info Complete`: `Info Incomplete`;
|
||||||
|
},
|
||||||
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
|
// Add text-danger or text-success class to the <td>
|
||||||
|
if (cellData == 1) {
|
||||||
|
$(td).addClass('text-success');
|
||||||
|
} else {
|
||||||
|
$(td).addClass('text-danger');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "User Details",
|
||||||
|
"data": "id",
|
||||||
|
"render": function (data, type, row, meta) {
|
||||||
|
if (!row.role.includes("SuperAdmin") && !row.role.includes("SystemAdmin")) {
|
||||||
|
var detailsButton = `<button type="button" class="btn btn-danger details-btn" data-id="${data}">Details</button>`;
|
||||||
|
return detailsButton;
|
||||||
|
} else {
|
||||||
|
return ""; // Return empty string if role is "SuperAdmin" or "SystemAdmin"
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Delete",
|
"title": "Delete",
|
||||||
@ -160,29 +223,59 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
order: [[5, 'asc']],
|
||||||
})
|
})
|
||||||
|
|
||||||
// Attach click event listener to the delete buttons
|
// Attach click event listener to the button
|
||||||
|
$('#userDatatable tbody').on('change', '.role-select', function () {
|
||||||
|
const userId = $(this).data('id');
|
||||||
|
const role = $(this).val();
|
||||||
|
self.selectedRole[userId] = role;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach click event listener to the update button
|
||||||
|
$('#userDatatable tbody').on('click', '.update-btn', function () {
|
||||||
|
const userId = $(this).data('id');
|
||||||
|
const thisUserRole = self.selectedRole[userId];
|
||||||
|
self.updateInfo(thisUserRole, userId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach click event listener to the delete button
|
||||||
$('#itemDatatable tbody').on('click', '.delete-btn', function () {
|
$('#itemDatatable tbody').on('click', '.delete-btn', function () {
|
||||||
const itemId = $(this).data('id');
|
const itemId = $(this).data('id');
|
||||||
self.deleteItem(itemId);
|
self.deleteItem(itemId);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#itemDatatable tbody').on('click', '.print-btn', function () {
|
|
||||||
const itemId = $(this).data('id');
|
|
||||||
var $row = $(this).closest('tr'); // get the row containing the button
|
|
||||||
var imageSrc = $row.find('img').attr('src'); // find the img element in the row and get its src
|
|
||||||
// console.log(imageSrc);
|
|
||||||
self.printItem(itemId, imageSrc);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
},
|
},
|
||||||
|
async updateInfo(thisUserRole, thisUserId) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const response = await fetch(`/AdminAPI/UpdateUserStatusAndRole/${thisUserId}`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(thisUserRole)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to update role');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Role updated successfully');
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Failed to update role:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log("User ID:" + thisUserId + " Role:" + thisUserRole);
|
||||||
|
|
||||||
|
//How to reload the table with new data from this.userList
|
||||||
|
|
||||||
|
this.fetchUsers();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
$(function () {
|
|
||||||
app.mount('#app');
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
<p><h5>User ID: @Model?.Id</h5></p>
|
<p><h5>User ID: @Model?.Id</h5></p>
|
||||||
<p><h5>User Name: @Model?.UserName</h5></p>
|
<p><h5>User Name: @Model?.UserName</h5></p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form>
|
<form v-on:submit.prevent="updateInfo">
|
||||||
<div class="col-md-6 col-lg-6">
|
<div class="col-md-6 col-lg-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="company">Company</label>
|
<label for="company">Company</label>
|
||||||
@ -42,6 +42,11 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6 col-lg-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-primary" type="submit">Update</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -68,7 +73,6 @@
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchModule();
|
|
||||||
this.fetchCompanies();
|
this.fetchCompanies();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -104,34 +108,25 @@
|
|||||||
console.error('Error fetching products:', error);
|
console.error('Error fetching products:', error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchModule() {
|
|
||||||
fetch('/AdminAPI/GetUserList', {
|
|
||||||
method: 'POST'
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.length > 0) {
|
|
||||||
this.userList = data.length ? data : [];
|
|
||||||
}
|
|
||||||
this.initiateTable();
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('There was a problem with the fetch operation:', error);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async updateInfo() {
|
async updateInfo() {
|
||||||
|
if (!this.selectedDepartment) {
|
||||||
|
alert("Please select a valid department.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const uid = @Model?.Id;
|
const uid = @Model?.Id;
|
||||||
try {
|
try {
|
||||||
// Show the loading modal
|
// Show the loading modal
|
||||||
$('#loadingModal').modal('show');
|
$('#loadingModal').modal('show');
|
||||||
|
const payload = {
|
||||||
|
departmentId: this.selectedDepartment,
|
||||||
|
};
|
||||||
// Perform the fetch request
|
// Perform the fetch request
|
||||||
const response = await fetch(`/IdentityAPI/UserComptDeptAssignment/${uid}`, {
|
const response = await fetch(`/IdentityAPI/UserComptDeptAssignment/${uid}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(this.selectedDepartment),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if the response is OK
|
// Check if the response is OK
|
||||||
@ -141,15 +136,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.fetchCompDept();
|
window.location.href = data.redirectUrl;
|
||||||
$('#registerCompDept').modal('hide');
|
|
||||||
alert("Company and department successfully added");
|
alert("Company and department successfully added");
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('Failed to add company and department:', error);
|
console.error('Failed to add company and department:', error);
|
||||||
alert(error.message);
|
const message = error.message || "An unexpected error occurred. Please try again.";
|
||||||
|
alert(message);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
$('#loadingModal').on('shown.bs.modal', resolve);
|
||||||
|
});
|
||||||
$('#loadingModal').modal('hide');
|
$('#loadingModal').modal('hide');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -73,6 +73,11 @@
|
|||||||
<div class="modal fade" id="loadingModal" data-bs-backdrop="static" tabindex="-1" aria-hidden="true" style="z-index: 1051;">
|
<div class="modal fade" id="loadingModal" data-bs-backdrop="static" tabindex="-1" aria-hidden="true" style="z-index: 1051;">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="closeModal" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="modal-body text-center">
|
<div class="modal-body text-center">
|
||||||
<div class="spinner-border text-primary" role="status">
|
<div class="spinner-border text-primary" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user