From e5ba9aedd77b90d67cd2b39af325dcb0fc80defa Mon Sep 17 00:00:00 2001 From: devmrko Date: Tue, 23 Jun 2026 14:34:19 +0900 Subject: [PATCH] [Developer] #424 load permission rule columns dynamically --- .../service/ProtectedObjectService.java | 4 +++ .../web/PermissionController.java | 29 +++++++++++++++++++ src/main/resources/static/js/app.js | 28 +++++++++++++----- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java b/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java index 4c15fa8..f49d95e 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java @@ -33,6 +33,10 @@ public class ProtectedObjectService { return mapper.findDatabaseObjects(); } + public List findDatabaseColumns(String owner, String objectName) { + return mapper.findDatabaseColumns(owner, objectName); + } + public ProtectedObject assertEnabled(long objectId) { ProtectedObject object = mapper.findById(objectId); if (object == null || !object.enabled()) { diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java b/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java index beb559d..c018e94 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java @@ -12,6 +12,7 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller @@ -28,6 +29,34 @@ public class PermissionController { this.protectedObjectService = protectedObjectService; } + @GetMapping("/permissions/object-columns") + @ResponseBody + public List objectColumns(@RequestParam String objectRef) { + if (objectRef == null || objectRef.isBlank()) { + return List.of(); + } + if (objectRef.startsWith("protected:")) { + long objectId; + try { + objectId = Long.parseLong(objectRef.substring("protected:".length())); + } catch (NumberFormatException exception) { + return List.of(); + } + return protectedObjectService.findColumns(objectId).stream() + .map(column -> column.columnName()) + .toList(); + } + if (objectRef.startsWith("db:")) { + String value = objectRef.substring("db:".length()); + int dot = value.indexOf('.'); + if (dot < 1 || dot == value.length() - 1) { + return List.of(); + } + return protectedObjectService.findDatabaseColumns(value.substring(0, dot), value.substring(dot + 1)); + } + return List.of(); + } + @GetMapping("/permissions") public String permissions(Model model) { var objects = protectedObjectService.findEnabled(); diff --git a/src/main/resources/static/js/app.js b/src/main/resources/static/js/app.js index 0412d2b..85ed874 100644 --- a/src/main/resources/static/js/app.js +++ b/src/main/resources/static/js/app.js @@ -28,13 +28,7 @@ function filterUserRoleDetail() { empty.hidden = shown !== 0; } -function syncRuleColumnOptions() { - const objectSelect = document.querySelector('select[name="objectRef"]'); - if (!objectSelect) { - return; - } - const selectedOption = objectSelect.options[objectSelect.selectedIndex]; - const columns = (selectedOption?.dataset.columns || '').split(',').filter(Boolean); +function renderRuleColumnOptions(columns) { document.querySelectorAll('.rule-column-select').forEach((select) => { const current = select.value; select.innerHTML = '' + columns @@ -46,6 +40,26 @@ function syncRuleColumnOptions() { }); } +async function syncRuleColumnOptions() { + const objectSelect = document.querySelector('select[name="objectRef"]'); + if (!objectSelect) { + return; + } + const selectedOption = objectSelect.options[objectSelect.selectedIndex]; + const fallbackColumns = (selectedOption?.dataset.columns || '').split(',').filter(Boolean); + renderRuleColumnOptions(fallbackColumns); + try { + const response = await fetch(`/permissions/object-columns?objectRef=${encodeURIComponent(objectSelect.value)}`); + if (!response.ok) { + return; + } + const columns = await response.json(); + renderRuleColumnOptions(Array.isArray(columns) ? columns : fallbackColumns); + } catch (error) { + renderRuleColumnOptions(fallbackColumns); + } +} + document.addEventListener('DOMContentLoaded', () => { const master = document.getElementById('userRoleMaster'); if (master) {