This commit is contained in:
MOHD ARIFF 2024-12-13 16:30:09 +08:00
parent 45a94c99fc
commit 3cfcfd7a3a
9 changed files with 352 additions and 261 deletions

View File

@ -2,9 +2,82 @@
@model AccessDeniedModel @model AccessDeniedModel
@{ @{
ViewData["Title"] = "Access denied"; ViewData["Title"] = "Access denied";
@inject UserManager<UserModel> _userManager
var user = await _userManager.GetUserAsync(User);
if (user != null)
{
var userComDept = user.departmentId;
var userRole = await _userManager.GetRolesAsync(user);
}
} }
<header> <header id="deniedHeader">
<h1 class="text-danger">@ViewData["Title"]</h1> <template v-if="ldapUserInfo.role.length == 0"><p class="text-danger">You do not have access to this resource because you have no role. Please contact the system administrator.</p></template>
<p class="text-danger">You do not have access to this resource.</p> <template v-else><p class="text-danger">You do not have access to this resource.</p></template>
</header> </header>
@section Scripts {
<script>
if (typeof jQuery === 'undefined') {
console.error('jQuery is not loaded.');
}
$(function () {
app.mount('#deniedHeader');
});
const app = Vue.createApp({
data() {
return {
ldapUserInfo: {
role: [],
},
};
},
mounted() {
this.getUserInfo();
},
watch: {
},
methods: {
async getUserInfo() {
try {
// Show the loading modal
$('#loadingModal').modal('show');
// Perform the fetch request
const response = await fetch('/IdentityAPI/GetUserInformation', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
// Check if the response is OK
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message);
}
const data = await response.json();
if (data.userInfo) {
console.log(data.userInfo)
this.ldapUserInfo = data.userInfo
} else {
console.error('Get user failed:', data);
}
}
catch (error) {
console.error('Error getting user information:', error);
}
finally {
await new Promise(resolve => {
$('#loadingModal').on('shown.bs.modal', resolve);
});
$('#loadingModal').modal('hide');
}
},
},
});
</script>
}

View File

@ -5,10 +5,19 @@
ViewData["Title"] = "Log in"; ViewData["Title"] = "Log in";
} }
<h1>@ViewData["Title"]</h1> <div class="row" id="systemLogin">
<div class="row"> <div class="row">
<div class="col-md-4"> <h2><label class="col-md-2">Login Type</label></h2>
<section> <div class="btn-group col-md-4" role="group" aria-label="Login type">
<input type="radio" class="btn-check" name="loginType" id="local-login" value="Local" v-model="loginType">
<label class="btn btn-outline-primary" for="local-login">Local</label>
<input type="radio" class="btn-check" name="loginType" id="ad-login" value="AD" v-model="loginType" checked>
<label class="btn btn-outline-primary" for="ad-login">AD</label>
</div>
</div>
<div class="row">
<div class="col-md-4" v-if="loginType == 'Local'">
<form id="account" method="post"> <form id="account" method="post">
<h2>Use a local account to log in.</h2> <h2>Use a local account to log in.</h2>
<hr /> <hr />
@ -23,32 +32,14 @@
<label asp-for="Input.Password" class="form-label">Password</label> <label asp-for="Input.Password" class="form-label">Password</label>
<span asp-validation-for="Input.Password" class="text-danger"></span> <span asp-validation-for="Input.Password" class="text-danger"></span>
</div> </div>
<div class="checkbox mb-3">
<label asp-for="Input.RememberMe" class="form-label">
<input class="form-check-input" asp-for="Input.RememberMe" />
@Html.DisplayNameFor(m => m.Input.RememberMe)
</label>
</div>
<div> <div>
<button id="login-submit" type="submit" class="w-100 btn btn-lg btn-primary">Log in</button> <button id="login-submit" type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
</div> </div>
<div>
<p>
<a id="forgot-password" asp-page="./ForgotPassword">Forgot your password?</a>
</p>
<p>
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
</p>
<p>
<a id="resend-confirmation" asp-page="./ResendEmailConfirmation">Resend email confirmation</a>
</p>
</div>
</form> </form>
</section>
</div> </div>
<div class="col-md-4" id="ldapLogin"> <div class="col-md-4" v-if="loginType == 'AD'">
<form v-on:submit.prevent="ldapLogin" id="login" method="post"> <form v-on:submit.prevent="ldapLogin" id="login" method="post">
<h2>Use a local account to log in.</h2> <h2>Use a AD account to log in.</h2>
<hr /> <hr />
<div class="text-danger" role="alert"></div> <div class="text-danger" role="alert"></div>
<div class="form-floating mb-3"> <div class="form-floating mb-3">
@ -97,6 +88,7 @@
</section> </section>
</div> </div>
</div> </div>
</div>
@section Scripts { @section Scripts {
<partial name="_ValidationScriptsPartial" /> <partial name="_ValidationScriptsPartial" />
@ -104,12 +96,13 @@
<script> <script>
$(function () { $(function () {
app.mount('#ldapLogin'); app.mount('#systemLogin');
}); });
const app = Vue.createApp({ const app = Vue.createApp({
data() { data() {
return { return {
loginType: 'AD',
ldapLoginInfo: { ldapLoginInfo: {
username: '', username: '',
password: '', password: '',
@ -123,50 +116,68 @@
}, },
methods: { methods: {
ldapLogin() { async ldapLogin() {
console.log(JSON.stringify(this.ldapLoginInfo)) try {
fetch('/AdminAPI/LdapLogin', { // Show the loading modal
$('#loadingModal').modal('show');
// Perform the fetch request
const response = await fetch('/IdentityAPI/LdapLogin', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json',
}, },
body: JSON.stringify(this.ldapLoginInfo) body: JSON.stringify(this.ldapLoginInfo),
}) });
.then(response => {
// Check if the response is OK
if (!response.ok) { if (!response.ok) {
throw new Error('Name module already exist'); const errorData = await response.json();
throw new Error(errorData.message);
} }
return response.json();
}) const data = await response.json();
.then(data => {
console.log(data); // Redirect if a URL is provided
if (data.redirectUrl) { if (data.redirectUrl) {
window.location.href = data.redirectUrl; window.location.href = data.redirectUrl;
} } else {
else
{
console.error('Login failed:', data); console.error('Login failed:', data);
alert('Login failed.');
} }
}) }
.catch(error => { catch (error) {
console.error('Error during LDAP login:', error); console.error('Error during LDAP login:', error);
alert('Failed to login: ' + error.message); alert(error.message);
}
finally {
await new Promise(resolve => {
$('#loadingModal').on('shown.bs.modal', resolve);
}); });
$('#loadingModal').modal('hide');
}
}, },
fetchControllerMethodList() { async fetchControllerMethodList() {
fetch('/AdminAPI/GetListClassAndMethodInformation', { try {
method: 'POST' const response = await fetch('/AdminAPI/GetListClassAndMethodInformation', {
}) method: 'POST',
.then(response => response.json()) });
.then(data => {
if (data != null) { if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
// Assign data if it exists
if (data) {
this.controllerMethodData = data; this.controllerMethodData = 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);
}); }
}, },
}, },
}); });
</script> </script>

View File

@ -20,8 +20,6 @@ namespace PSTW_CentralSystem.Controllers.API
private readonly IdentityDBContext _authDbContext; private readonly IdentityDBContext _authDbContext;
private readonly UserManager<UserModel> _userManager; private readonly UserManager<UserModel> _userManager;
private readonly SignInManager<UserModel> _signInManager; private readonly SignInManager<UserModel> _signInManager;
// Communication Key for API. Not API authentication key
private readonly string _commKey = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF4NW42anlkNlpTYzZNSE1Zem9qaApUbldpYTIra2pud2ZNbVhpSWlyK0RadjM2cEVGMGhRUWFLaWpaMWtyMGNiT25Ha2d2QnNwTzNiYkFua0E3SWwzCk4zM3NNYWdQV0JOQzZyVm1jT04zNEhDSWJCM0hvQXFYQUtkSHFUOGZneklMRzFhRzdxK2h4RDZhZzZsemhTMnEKdDA1bHdNc0hONWpOdmVNNnFWalRnTVB4aEFOMUhnUTkrd1lRWFh5bnZYYUo5OUNySHBqS21WdUt2VUh6WXdlRwp6SnBtYXZOclc4bE9oM1lMeVNuUVU5bjRrdURubGc1OWNHeUtKbzJ2YUxZbll4MkR1ZDNabzBXMHRMWGd0dlQyCjVXdVFsY0NVbldvaVpBV1JBTGI3anRpcTF0MGY5eVBiV2gxYXpMMjFoL3QvckJUMXNCL2FQd2kzRCt3MnBUR00KeVFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==";
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)
{ {
@ -97,13 +95,13 @@ namespace PSTW_CentralSystem.Controllers.API
var userRole = await _userManager.GetRolesAsync(user??new UserModel()); var userRole = await _userManager.GetRolesAsync(user??new UserModel());
List<UserModel> userInfo = new List<UserModel>(); List<UserModel> userInfo = new List<UserModel>();
if (userRole == null || userRole.Count == 0)
{
// Fetch all users excluding those with roles SuperAdmin or SystemAdmin // Fetch all users excluding those with roles SuperAdmin or SystemAdmin
var allUsers = await _authDbContext.Users var allUsers = await _authDbContext.Users
.Include(u => u.Department).ThenInclude(d => d!.Company) .Include(u => u.Department)
.ToListAsync(); .ToListAsync();
if (userRole == null || userRole.Count == 0)
{
foreach (var u in allUsers) foreach (var u in allUsers)
{ {
var roles = await _userManager.GetRolesAsync(u); var roles = await _userManager.GetRolesAsync(u);
@ -115,126 +113,22 @@ namespace PSTW_CentralSystem.Controllers.API
} }
else else
{ {
userInfo = await _authDbContext.Users.Include(u => u.Department).ThenInclude(d => d!.Company).ToListAsync(); userInfo = await _authDbContext.Users.Include(u => u.Department).ToListAsync();
} }
var userList = userInfo.Select(u => new
return Ok(new { UserInfo = userInfo }); {
id = u.Id,
email = u.NormalizedEmail,
company = u.Department?.Company?.CompanyName,
department = u.Department,
role = _userManager.GetRolesAsync(u).Result
}).ToList();
return Ok(new { UserInfo = userList });
} }
catch (Exception ex) catch (Exception ex)
{ {
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")]
public async Task<IActionResult> LdapLogin([FromBody] LdapLoginCredential ldapLoginInfo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
byte[] noFormatString = Convert.FromBase64String(_commKey);
string initUrlKey = Encoding.UTF8.GetString(noFormatString);
string jsonData = JsonSerializer.Serialize(ldapLoginInfo);
RSA rsaBase = RSA.Create();
rsaBase.ImportFromPem(initUrlKey.ToCharArray());
byte[] rsaData = rsaBase.Encrypt(Encoding.UTF8.GetBytes(jsonData), RSAEncryptionPadding.Pkcs1);
string rsaDataBase64 = Convert.ToBase64String(rsaData);
string ldapUrl = "http://192.168.11.231/api/ldap/";
string ldapUrlResult = "";
using (HttpClient httpClient = new HttpClient())
{
try
{
StringContent rsaDataB64HttpContent = new(rsaDataBase64, Encoding.UTF8);
HttpResponseMessage ldapUrlResponse = await httpClient.PostAsync(ldapUrl, rsaDataB64HttpContent);
ldapUrlResponse.EnsureSuccessStatusCode();
if (ldapUrlResponse.IsSuccessStatusCode)
{
ldapUrlResult = await ldapUrlResponse.Content.ReadAsStringAsync();
}
}
catch (Exception e)
{
return BadRequest(new { Message = $"Message: {e.Message}\nException Caught!" });
}
}
userLdapInfo userLdapInfo = JsonSerializer.Deserialize<userLdapInfo>(ldapUrlResult)!;
userInfo userInfo = userLdapInfo.UserInfo;
if (!userLdapInfo.Authenticated)
{
return BadRequest(new { Message = "Login Failed" });
}
UserModel ldapuser = new UserModel()
{
FullName = userInfo.Username,
UserName = userInfo.Email,
NormalizedUserName = userInfo.Email.ToUpper(),
Email = userInfo.Email,
NormalizedEmail = userInfo.Email.ToUpper(),
EmailConfirmed = true,
PhoneNumberConfirmed = false,
TwoFactorEnabled = false,
LockoutEnabled = false,
AccessFailedCount = 0,
};
var existUser = await doUserExists(ldapuser.Email);
if (existUser == null)
{
await _userManager.CreateAsync(ldapuser);
//await _userManager.SetLockoutEnabledAsync(ldapuser, false);
//return RedirectToAction("AssignRoleAfterLdap", "IdentityController");
return Ok(new { RedirectUrl = Url.Action("RoleAssignment", "Identity") });
};
await _signInManager.SignInAsync(existUser, false);
//return RedirectToAction("Index", "HomeController");
return Ok(new { RedirectUrl = Url.Action("Index", "Home") });
}
public async Task<UserModel?> doUserExists(string username)
{
var user = await _userManager.FindByNameAsync(username);
return user != null ? user : null;
}
class userLdapInfo()
{
public required bool Authenticated { get; set; }
public required userInfo UserInfo { get; set; }
}
class userInfo()
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required string DisplayName { get; set; }
public required string Description { get; set; }
public required string Username { get; set; }
public required string Office { get; set; }
public required string Email { get; set; }
public required string Street { get; set; }
public required string City { get; set; }
public required string State { get; set; }
public required string ZipCode { get; set; }
public required string Country { get; set; }
public required string Home { get; set; }
public required string Mobile { get; set; }
}
} }
} }

View File

@ -3,6 +3,9 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext; using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models; using PSTW_CentralSystem.Models;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace PSTW_CentralSystem.Controllers.API namespace PSTW_CentralSystem.Controllers.API
{ {
[ApiController] [ApiController]
@ -13,15 +16,20 @@ namespace PSTW_CentralSystem.Controllers.API
private readonly ILogger<IdentityAPI> _logger; private readonly ILogger<IdentityAPI> _logger;
private readonly IdentityDBContext _authDbContext; private readonly IdentityDBContext _authDbContext;
private readonly UserManager<UserModel> _userManager; private readonly UserManager<UserModel> _userManager;
private readonly SignInManager<UserModel> _signInManager;
// Communication Key for API. Not API authentication key
private readonly string _commKey = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF4NW42anlkNlpTYzZNSE1Zem9qaApUbldpYTIra2pud2ZNbVhpSWlyK0RadjM2cEVGMGhRUWFLaWpaMWtyMGNiT25Ha2d2QnNwTzNiYkFua0E3SWwzCk4zM3NNYWdQV0JOQzZyVm1jT04zNEhDSWJCM0hvQXFYQUtkSHFUOGZneklMRzFhRzdxK2h4RDZhZzZsemhTMnEKdDA1bHdNc0hONWpOdmVNNnFWalRnTVB4aEFOMUhnUTkrd1lRWFh5bnZYYUo5OUNySHBqS21WdUt2VUh6WXdlRwp6SnBtYXZOclc4bE9oM1lMeVNuUVU5bjRrdURubGc1OWNHeUtKbzJ2YUxZbll4MkR1ZDNabzBXMHRMWGd0dlQyCjVXdVFsY0NVbldvaVpBV1JBTGI3anRpcTF0MGY5eVBiV2gxYXpMMjFoL3QvckJUMXNCL2FQd2kzRCt3MnBUR00KeVFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==";
public IdentityAPI(ILogger<IdentityAPI> logger, IdentityDBContext authDbContext, UserManager<UserModel> userManager)
public IdentityAPI(ILogger<IdentityAPI> logger, IdentityDBContext authDbContext, UserManager<UserModel> userManager, SignInManager<UserModel> signInManager)
{ {
_logger = logger; _logger = logger;
_authDbContext = authDbContext; _authDbContext = authDbContext;
_userManager = userManager; _userManager = userManager;
_signInManager = signInManager;
} }
[HttpPost("GetUserInformation/")] [HttpPost("GetUserInformation")]
public async Task<IActionResult> GetUserInformation() public async Task<IActionResult> GetUserInformation()
{ {
try try
@ -30,7 +38,7 @@ namespace PSTW_CentralSystem.Controllers.API
var userRole = await _userManager.GetRolesAsync(user!); var userRole = await _userManager.GetRolesAsync(user!);
if (user == null) if (user == null)
{ {
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); return NotFound(new { message = $"Unable to load user with ID '{_userManager.GetUserId(User)}'."});
} }
var userInfo = await _authDbContext.Users.Include(u => u.Department).Select(u => new var userInfo = await _authDbContext.Users.Include(u => u.Department).Select(u => new
@ -44,7 +52,7 @@ namespace PSTW_CentralSystem.Controllers.API
if (userInfo == null) if (userInfo == null)
{ {
return NotFound("User not found"); return NotFound(new { message = "User not found" });
} }
return Ok(new { UserInfo = userInfo }); return Ok(new { UserInfo = userInfo });
@ -54,5 +62,118 @@ 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")]
public async Task<IActionResult> LdapLogin([FromBody] LdapLoginCredential ldapLoginInfo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
byte[] noFormatString = Convert.FromBase64String(_commKey);
string initUrlKey = Encoding.UTF8.GetString(noFormatString);
string jsonData = JsonSerializer.Serialize(ldapLoginInfo);
RSA rsaBase = RSA.Create();
rsaBase.ImportFromPem(initUrlKey.ToCharArray());
byte[] rsaData = rsaBase.Encrypt(Encoding.UTF8.GetBytes(jsonData), RSAEncryptionPadding.Pkcs1);
string rsaDataBase64 = Convert.ToBase64String(rsaData);
string ldapUrl = "http://192.168.11.231/api/ldap/";
string ldapUrlResult = "";
using (HttpClient httpClient = new HttpClient())
{
try
{
StringContent rsaDataB64HttpContent = new(rsaDataBase64, Encoding.UTF8);
HttpResponseMessage ldapUrlResponse = await httpClient.PostAsync(ldapUrl, rsaDataB64HttpContent);
ldapUrlResponse.EnsureSuccessStatusCode();
if (ldapUrlResponse.IsSuccessStatusCode)
{
ldapUrlResult = await ldapUrlResponse.Content.ReadAsStringAsync();
}
}
catch (Exception e)
{
return BadRequest(new { Message = $"Message: {e.Message}\nException Caught!" });
}
}
userLdapInfo userLdapInfo = JsonSerializer.Deserialize<userLdapInfo>(ldapUrlResult)!;
if (!userLdapInfo.Authenticated)
{
return BadRequest(new { Message = $"Login Failed. {userLdapInfo.Response}" });
}
userInfo userInfo = userLdapInfo.UserInfo!;
UserModel ldapuser = new UserModel()
{
FullName = userInfo!.Username,
UserName = userInfo.Email,
NormalizedUserName = userInfo.Email.ToUpper(),
Email = userInfo.Email,
NormalizedEmail = userInfo.Email.ToUpper(),
EmailConfirmed = true,
PhoneNumberConfirmed = false,
TwoFactorEnabled = false,
LockoutEnabled = false,
AccessFailedCount = 0,
};
var existUser = await doUserExists(ldapuser.Email);
if (existUser == null)
{
await _userManager.CreateAsync(ldapuser);
//await _userManager.SetLockoutEnabledAsync(ldapuser, false);
//return RedirectToAction("AssignRoleAfterLdap", "IdentityController");
return Ok(new { RedirectUrl = Url.Action("ComDeptAssignment", "Identity") });
};
await _signInManager.SignInAsync(existUser, false);
//return RedirectToAction("Index", "HomeController");
return Ok(new { RedirectUrl = Url.Action("Index", "Home") });
}
public async Task<UserModel?> doUserExists(string username)
{
var user = await _userManager.FindByNameAsync(username);
return user != null ? user : null;
}
class userLdapInfo()
{
public required bool Authenticated { get; set; }
public userInfo? UserInfo { get; set; }
public string? Response { get; set; }
}
class userInfo()
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required string DisplayName { get; set; }
public required string Description { get; set; }
public required string Username { get; set; }
public required string Office { get; set; }
public required string Email { get; set; }
public required string Street { get; set; }
public required string City { get; set; }
public required string State { get; set; }
public required string ZipCode { get; set; }
public required string Country { get; set; }
public required string Home { get; set; }
public required string Mobile { get; set; }
}
} }
} }

View File

@ -6,7 +6,7 @@ using System.Diagnostics;
namespace PSTW_CentralSystem.Controllers namespace PSTW_CentralSystem.Controllers
{ {
//[Authorize(Policy = "RoleModulePolicy")] [Authorize(Policy = "RoleModulePolicy")]
public class AdminController : Controller public class AdminController : Controller
{ {
private readonly IdentityDBContext _authDbContext; private readonly IdentityDBContext _authDbContext;

View File

@ -2,6 +2,9 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using PSTW_CentralSystem.DBContext; using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models; using PSTW_CentralSystem.Models;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace PSTW_CentralSystem.Controllers namespace PSTW_CentralSystem.Controllers
{ {
@ -19,7 +22,7 @@ namespace PSTW_CentralSystem.Controllers
_userManager = userManager; _userManager = userManager;
} }
public async Task<IActionResult> RoleAssignment() public async Task<IActionResult> ComDeptAssignment()
{ {
var thisUser = await _userManager.GetUserAsync(User); var thisUser = await _userManager.GetUserAsync(User);
return View(thisUser.Id); return View(thisUser.Id);

View File

@ -17,8 +17,7 @@
<h4 class="card-title">Latest Posts</h4> <h4 class="card-title">Latest Posts</h4>
<div class="col-md-12 col-lg-12"> <div class="col-md-12 col-lg-12">
<div> <div>
<table class="table table-bordered border-primary" id="userDatatable"> <table class="table table-bordered table-hover table-striped no-wrap" id="userDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
</table>
</div> </div>
</div> </div>
</div> </div>
@ -157,27 +156,6 @@
} }
], ],
responsive: true, responsive: true,
drawCallback: function (settings) {
// Generate QR codes after rows are rendered
const api = this.api();
api.rows().every(function () {
const data = this.data(); // Row data
const containerId = `qr${data.uniqueID}`;
const container = $(`#${containerId}`);
// console.log(container[0]);
if (container) {
// Generate QR code only if not already generated
new QRCode(container[0], {
text: data.qrString,
width: 150,
height: 150,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
}
});
},
}) })
// Attach click event listener to the delete buttons // Attach click event listener to the delete buttons

View File

@ -2,7 +2,7 @@
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@ *@
@{ @{
ViewData["Title"] = "Role Assignment"; ViewData["Title"] = "Company & Department Assignment";
Layout = "~/Views/Shared/_Layout.cshtml"; Layout = "~/Views/Shared/_Layout.cshtml";
int userId = ViewBag.UserId; int userId = ViewBag.UserId;
} }
@ -19,8 +19,7 @@
<h4 class="card-title">Latest Posts</h4> <h4 class="card-title">Latest Posts</h4>
<div class="col-md-12 col-lg-12"> <div class="col-md-12 col-lg-12">
<div> <div>
<table class="table table-bordered border-primary" id="userDatatable"> <table class="table table-bordered border-primary" id="userDatatable"></table>
</table>
</div> </div>
</div> </div>
</div> </div>

View File

@ -70,6 +70,18 @@
<div class="lds-pos"></div> <div class="lds-pos"></div>
</div> </div>
</div> </div>
<div class="modal fade" id="loadingModal" data-bs-backdrop="static" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-3">Please wait while we process your request...</p>
</div>
</div>
</div>
</div>
<!-- ============================================================== --> <!-- ============================================================== -->
<!-- Main wrapper - style you can find in pages.scss --> <!-- Main wrapper - style you can find in pages.scss -->
<!-- ============================================================== --> <!-- ============================================================== -->