This commit is contained in:
MOHD ARIFF 2024-11-21 16:32:12 +08:00
parent 3f3ad980b9
commit 54b2affe28
14 changed files with 18562 additions and 108 deletions

View File

@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models;
using System.Diagnostics;
using System.Reflection;
namespace PSTW_CentralSystem.Controllers.API
{
@ -21,11 +22,32 @@ namespace PSTW_CentralSystem.Controllers.API
_authDbContext = authDbContext;
}
[HttpPost("GetModuleInformation")]
public async Task<IActionResult> GetModuleInformation()
[HttpPost("GetClassAndMethodInformation")]
public async Task<IActionResult> GetClassAndMethodInformation(string moduleName)
{
var qcList = await _authDbContext.ModuleSettings.ToListAsync();
return Json(qcList);
var controllerAndMethodList = new object();
// Get the assembly containing the controllers
var assembly = Assembly.GetExecutingAssembly();
// Get all types in the assembly (controllers will typically be in the "Controllers" namespace)
//var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && type.Name.Contains("Controller") && type.Name != "AdminController") .ToList());
var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && type.Name.Contains(moduleName)).FirstOrDefault());
// Iterate over the controller types and get their methods
var methods = controllerTypes?.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.DeclaringType == controllerTypes) // Filter methods declared directly in the controller (ignoring inherited ones)
.Select(m => m.Name) // Get the method names
.ToList();
controllerAndMethodList = (new
{
Controller = controllerTypes?.Name,
Methods = methods
});
// Return the list as JSON
return Json(controllerAndMethodList);
}
}

View File

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext;
namespace PSTW_CentralSystem.Controllers.API
{
[ApiController]
[Route("[controller]")]
public class ModuleAPI : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly AuthDBContext _authDbContext;
public ModuleAPI(ILogger<HomeController> logger, AuthDBContext authDbContext)
{
_logger = logger;
_authDbContext = authDbContext;
}
[HttpPost("GetModuleInformation")]
public async Task<IActionResult> GetModuleInformation()
{
var qcList = await _authDbContext.ModuleSettings.ToListAsync();
return Json(qcList);
}
[HttpPost("GetXModuleInformation")]
public async Task<IActionResult> GetXModuleInformation(int? id)
{
var qcList = await _authDbContext.ModuleSettings.Where(x => x.SettingId == id).FirstOrDefaultAsync();
return Json(qcList);
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext;
namespace PSTW_CentralSystem.Controllers.API
{
[ApiController]
[Route("[controller]")]
public class RoleAPI : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly AuthDBContext _authDbContext;
public RoleAPI(ILogger<HomeController> logger, AuthDBContext authDbContext)
{
_logger = logger;
_authDbContext = authDbContext;
}
[HttpPost("GetRoleList")]
public async Task<IActionResult> GetRoleList()
{
var roleList = await _authDbContext.Roles.Where(r => r.Id != 1 && r.Id != 2).ToListAsync();
return Json(roleList);
}
}
}

View File

@ -42,6 +42,10 @@ namespace PSTW_CentralSystem.Controllers
return View(moduleSettings);
}
public IActionResult ModuleCreate()
{
return View();
}
}
}

View File

@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace PSTW_CentralSystem.Controllers.Inventory
{
public class InventoryController : Controller
{
// GET: Inventory
public ActionResult Index()
{
return View();
}
// GET: Inventory/Details/5
public ActionResult Details(int id)
{
return View();
}
// GET: Inventory/Create
public ActionResult Create()
{
return View();
}
// POST: Inventory/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: Inventory/Edit/5
public ActionResult Edit(int id)
{
return View();
}
// POST: Inventory/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: Inventory/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: Inventory/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
}
}

View File

@ -37,6 +37,7 @@ namespace PSTW_CentralSystem.CustomPolicy
if (checkIfSuperAdmin())
{
context.Succeed(requirement);
return;
}
else {
checkModuleExistOrNot();
@ -66,6 +67,7 @@ namespace PSTW_CentralSystem.CustomPolicy
if (registeredModule == null)
{
context.Fail();
return;
}
else
{
@ -78,6 +80,7 @@ namespace PSTW_CentralSystem.CustomPolicy
if (registeredModule.ModuleStatus == 0)
{
context.Fail();
return;
}
}
@ -87,6 +90,7 @@ namespace PSTW_CentralSystem.CustomPolicy
if (allowedUserTypes == "Public" || userRole.Any(role => allowedUserTypes.Contains(role)))
{
context.Succeed(requirement);
return;
}
else if (currentUser != null && allowedUserTypes == "Registered User" )
{
@ -95,6 +99,7 @@ namespace PSTW_CentralSystem.CustomPolicy
else
{
context.Fail();
return;
}
}
@ -116,15 +121,18 @@ namespace PSTW_CentralSystem.CustomPolicy
if (userRole.Any(role => allowedUserTypes.Contains(role)) || allowedUserTypes.Contains("All")) // Check if the user role is allowed, allowing only registered user to access.
{
context.Succeed(requirement);
return;
}
else
{
context.Fail();
return;
}
}
else // No method is registered to allow all method to be accessed
{
context.Succeed(requirement);
return;
}
}
}

View File

@ -27,6 +27,8 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\JSA\API\" />
<Folder Include="Controllers\Inventory\API\" />
<Folder Include="Logs\" />
<Folder Include="Migrations\" />
</ItemGroup>

View File

@ -123,7 +123,7 @@
},
methods: {
fetchModule() {
fetch('/AdminAPI/GetModuleInformation', {
fetch('/ModuleAPI/GetModuleInformation', {
method: 'POST'
})
.then(response => response.json())
@ -151,7 +151,7 @@
$('#confirm-dialog').modal('show'); // Show the modal
},
confirmDelete(module) {
fetch('/AdminAPI/DeleteModule/' + module.settingId, {
fetch('/ModuleAPI/DeleteModule/' + module.settingId, {
method: 'POST'
})
.then(response => {
@ -172,6 +172,9 @@
}
}
})
$(function () {
app.mount('#app');
});
</script>
}

View File

@ -7,75 +7,91 @@
Layout = "~/Views/Shared/_Layout.cshtml";
}
<p>
<a asp-action="CreateModule">Create New</a>
</p>
<div class="row" id="app">
<div class="col-md-12 col-lg-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">{{module.moduleName}}</h4>
<div class="col-md-12 col-lg-12">
<div v-if="moduleData">
<table class="table table-bordered border-primary">
<thead>
<tr>
<th>
ModuleName
</th>
<th>
Access Type
</th>
<th>
Configured Page
</th>
<th>
Description
</th>
<th>
ModuleStatus
</th>
<th>
Action
</th>
</tr>
</thead>
<tbody>
<tr v-for="module in moduleData">
<td class="align-middle">
{{module.moduleName}}
</td>
<td class="align-middle">
{{module.allowedUserType}}
</td>
<td class="align-middle">
<ul>
<li v-for="(method, index) in module.methodAllowedUserType" :key="index">
<strong>Method Name:</strong> {{ method.methodName }}<br>
<strong>Allowed User Types:</strong>
<span v-for="(userType, idx) in method.allowedUserTypesArray" :key="idx">
{{ userType }}<span v-if="idx < method.allowedUserTypesArray.length - 1">, </span>
</span>
<form v-on:submit.prevent="">
<div class="card">
<div class="card-body">
<h5 class="card-title">Settings</h5>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Name</label>
<div class="col-md-6">
<input type="text" class="form-control" name="moduleName" :value="moduleData.moduleName" readonly />
</div>
</div>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Access</label>
<div class="col-md-6">
<select class="form-select shadow-none mt-3" name="allowedUserType" v-model="moduleData.allowedUserType" style="height: 36px; width: 100%">
<optgroup label="General">
<option value="Public">Public</option>
<option value="Registered User">Registered User</option>
</optgroup>
<optgroup label="Role">
<option v-for="(roleType, index) in roleData" :key="index" :value="roleType.name">{{ roleType.name }}</option>
</optgroup>
</select>
</div>
</div>
<div v-show="moduleData && moduleData.allowedUserType == 'Registered User'">
<div class="form-group row">
<label class="col-md-3 mt-3">Available Method</label>
<div class="col-md-3">
<select class="form-select shadow-none mt-3" name="allowedUserType" v-model="selectedModule" style="height: 36px; width: 100%">
<option v-for="(methods, index) in availableMethod" :key="index" :value="methods">{{ methods }}</option>
</select>
</div>
<button class="btn col-md-3 f-icon mt-3 d-flex align-items-center" style="height: 36px; width: auto">
<i class=" fas fa-plus-square fa-lg"></i>&nbsp;Add method
</button>
</div>
<div class="form-group row">
<label class="col-md-3 mt-3">Add Method Rules</label>
<div class="col-md-9">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation" v-for="(setMethod, index) in moduleData.methodAllowedUserType" :key="index">
<a :class="['nav-link', activeTab === index ? 'active' : '']"
:id="'simple-tab-' + index"
data-bs-toggle="tab"
:href="'#simple-tabpanel-' + index"
role="tab"
:aria-controls="'simple-tabpanel-' + index"
:aria-selected="activeTab === index ? 'true' : 'false'">
{{ setMethod.methodName }}
</a>
</li>
</ul>
</td>
<td class="align-middle">
{{module.description}}
</td>
<td class="align-middle">
<span>
<i :class="{'far fa-lg fa-times-circle': module.moduleStatus === 0, 'far fa-lg fa-check-circle': module.moduleStatus === 1}"
:style="{color: (module.moduleStatus === 0 ? 'red' : 'limegreen')}">
</i>
</span>
</td>
<td class="align-middle">
<button class="btn btn-primary" v-on:click="editModule(module)">Edit</button> |
<button class="btn btn-danger delete-button" v-on:click="deleteModule(module)">Delete</button>
</td>
</tr>
</tbody>
</table>
<div class="tab-content pt-5" id="tab-content">
<div :class="['tab-pane', activeTab === index ? 'active' : '']" :id="'simple-tabpanel-' + index" role="tabpanel" :aria-labelledby="'simple-tab-' + index" v-for="(setMethod, index) in moduleData.methodAllowedUserType" :key="index">
<p>Tab {{ setMethod.methodName }} selected</p>
<div class="form-group row">
<label class="col-md-1">Role:</label>
<div class="col-md-6">
<select class="select2 form-select shadow-none mt-3" multiple="multiple" style="height: 36px; width: 100%" v-model="moduleData.methodAllowedUserType[index].allowedUserTypesArray
">
<option v-for="(roleType, index) in roleData" :key="index" :value="roleType.name">{{ roleType.name }}</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="border-top">
<div class="card-body">
<button type="button" class="btn btn-primary">
Save
</button>
</div>
</div>
</div>
</form>
</div>
<div v-else><p>... Loading</p></div>
</div>
@ -100,7 +116,7 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<input type="hidden" id="delete-id">
<a id="confirmButton" href="#" class="btn btn-danger" @@click="confirmDelete(selectedModule)">Confirm</a>
<a id="confirmButton" href="#" class="btn btn-danger" v-on:click="confirmDelete(selectedModule)">Confirm</a>
</div>
</div>
<div v-else><p>Loading...</p></div>
@ -111,48 +127,93 @@
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
<script>
</script>
<script>
const app = Vue.createApp({
data() {
return {
moduleData: null,
roleData: null,
controllerMethodData: null,
activeTab: null,
availableMethod: [],
selectedModule: null
};
},
mounted() {
this.fetchModule();
this.fetchXModule();
this.fetchControllerMethodList();
},
watch: {
// Watching allowedUserType directly
// 'moduleData.allowedUserType'(newVal, oldVal) {
// console.log(`allowedUserType changed from ${oldVal} to ${newVal}`);
// }
'moduleData.allowedUserType'(newVal, oldVal) {
// console.log(`allowedUserType changed from ${oldVal} to ${newVal}`);
this.filterAvailableMethods();
}
},
methods: {
fetchModule() {
fetch('/AdminAPI/GetModuleInformation', {
fetchXModule() {
var id = @Model.SettingId
fetch('/ModuleAPI/GetXModuleInformation?id=' + id, {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data.length > 0) {
this.moduleData = data.length ? data : [];
if (data != null) {
this.moduleData = data;
this.fetchRoleList();
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
editModule(module) {
// Check if the user ID exists
if (module.settingId) {
// Redirect the user to the edit user page
window.location.href = 'EditModule/' + module.settingId;
} else {
console.error('Module ID not found');
fetchRoleList() {
fetch('/RoleAPI/GetRoleList', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data != null) {
this.roleData = data;
this.$nextTick(() => {
$(".select2").select2(); // Initialize Select2 after DOM update
});
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
fetchControllerMethodList() {
var moduleName = '@Model.ModuleName'
fetch('/AdminAPI/GetClassAndMethodInformation?moduleName=' + moduleName, {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data != null) {
this.controllerMethodData = data;
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
deleteModule(module) {
this.selectedModule = module; // Set selected user
$('#confirm-dialog').modal('show'); // Show the modal
},
confirmDelete(module) {
fetch('/AdminAPI/DeleteModule/' + module.settingId, {
fetch('/ModuleAPI/DeleteModule/' + module.settingId, {
method: 'POST'
})
.then(response => {
@ -170,9 +231,15 @@
.catch(error => {
console.error('Failed to delete module with status:', error);
});
}
},
filterAvailableMethods() {
const moduleMethods = this.moduleData.methodAllowedUserType.map(method => method.methodName);
this.availableMethod = this.controllerMethodData.methods.filter(method => !moduleMethods.includes(method)); // exclude methods that are already in moduleMethods
},
}
})
$(function () {
app.mount('#app');
});
</script>
}

View File

@ -0,0 +1,10 @@
@{
ViewData["Title"] = "PSTW Centralized System";
}
<div class="row">
<div class="text-center">
<h1 class="display-4">Welcome To Invetory Module</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
</div>

View File

@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace PSTW_CentralSystem.Views.JSA
{
public class JSAController : Controller
{
// GET: JSAController
public ActionResult Index()
{
return View();
}
// GET: JSAController/Details/5
public ActionResult Details(int id)
{
return View();
}
// GET: JSAController/Create
public ActionResult Create()
{
return View();
}
// POST: JSAController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: JSAController/Edit/5
public ActionResult Edit(int id)
{
return View();
}
// POST: JSAController/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: JSAController/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: JSAController/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
}
}

View File

@ -24,14 +24,14 @@
sizes="16x16"
href="/assets/images/favicon.png" />
<!-- Custom CSS -->
<link href="/assets/libs/fullcalendar/dist/fullcalendar.min.css"
rel="stylesheet" />
<link href="/assets/extra-libs/calendar/calendar.css" rel="stylesheet" />
<link href="/dist/css/style.min.css" rel="stylesheet" />
<link rel="stylesheet" href="~/assets/libs/select2/dist/css/select2.min.css" />
<link rel="stylesheet" href="~/assets/libs/jquery-minicolors/jquery.minicolors.css" />
<link rel="stylesheet" href="~/assets/libs/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" />
<link rel="stylesheet" href="~/assets/libs/quill/dist/quill.snow.css" />
<link href="~/dist/css/style.min.css" rel="stylesheet" />
<!-- Vue Js CSS -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
@* <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script> *@
<script src="~/js/vue.global.js"></script>
@* <script src="~/js/vue.global.prod.js"></script> *@
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
@ -650,24 +650,30 @@
<!-- ============================================================== -->
<!-- All Jquery -->
<!-- ============================================================== -->
<script src="/assets/libs/jquery/dist/jquery.min.js"></script>
<script src="/dist/js/jquery.ui.touch-punch-improved.js"></script>
<script src="/dist/js/jquery-ui.min.js"></script>
<script src="~/assets/libs/jquery/dist/jquery.min.js"></script>
<script src="~/dist/js/jquery.ui.touch-punch-improved.js"></script>
<script src="~/dist/js/jquery-ui.min.js"></script>
<!-- Bootstrap tether Core JavaScript -->
<script src="/assets/libs/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/assets/libs/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<!-- slimscrollbar scrollbar JavaScript -->
<script src="/assets/libs/perfect-scrollbar/dist/perfect-scrollbar.jquery.min.js"></script>
<script src="/assets/extra-libs/sparkline/sparkline.js"></script>
<script src="~/assets/libs/perfect-scrollbar/dist/perfect-scrollbar.jquery.min.js"></script>
<script src="~/assets/extra-libs/sparkline/sparkline.js"></script>
<!--Wave Effects -->
<script src="/dist/js/waves.js"></script>
<script src="~/dist/js/waves.js"></script>
<!--Menu sidebar -->
<script src="/dist/js/sidebarmenu.js"></script>
<script src="~/dist/js/sidebarmenu.js"></script>
<!--Custom JavaScript -->
<script src="/dist/js/custom.min.js"></script>
<!-- this page js -->
<script src="/assets/libs/moment/min/moment.min.js"></script>
<script src="/assets/libs/fullcalendar/dist/fullcalendar.min.js"></script>
<script src="/dist/js/pages/calendar/cal-init.js"></script>
<script src="~/dist/js/custom.min.js"></script>
<!--Form JS-->
<script src="~/assets/libs/inputmask/dist/min/jquery.inputmask.bundle.min.js"></script>
<script src="~/dist/js/pages/mask/mask.init.js"></script>
<script src="~/assets/libs/select2/dist/js/select2.full.min.js"></script>
<script src="~/assets/libs/jquery-asColor/dist/jquery-asColor.min.js"></script>
<script src="~/assets/libs/jquery-asGradient/dist/jquery-asGradient.js"></script>
<script src="~/assets/libs/jquery-asColorPicker/dist/jquery-asColorPicker.min.js"></script>
<script src="~/assets/libs/jquery-minicolors/jquery.minicolors.min.js"></script>
<script src="~/assets/libs/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
<script src="~/assets/libs/quill/dist/quill.min.js"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>

18096
wwwroot/js/vue.global.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long