From 1c3894cb40349dfe2179cf94ff3ac0d9a9e46df1 Mon Sep 17 00:00:00 2001 From: devmrko Date: Thu, 25 Jun 2026 11:18:22 +0900 Subject: [PATCH] [Developer] #424 show VPD policy details --- .../domain/vpd/VpdPolicyDetail.java | 7 ++ .../vpdbackoffice/mapper/VpdPolicyMapper.java | 6 ++ .../service/VpdPolicyService.java | 67 +++++++++++++++++++ .../web/VpdPolicyController.java | 18 +++++ src/main/resources/mapper/VpdPolicyMapper.xml | 53 +++++++++------ .../fragments/vpd-policy-detail.html | 27 ++++++++ .../resources/templates/vpd-policies.html | 12 +++- 7 files changed, 167 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java create mode 100644 src/main/resources/templates/fragments/vpd-policy-detail.html diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java new file mode 100644 index 0000000..77454ed --- /dev/null +++ b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java @@ -0,0 +1,7 @@ +package com.cloudhandson.vpdbackoffice.domain.vpd; + +public record VpdPolicyDetail( + VpdPolicyView policy, + String ddl +) { +} diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java b/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java index 0a79d0d..c432f3f 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java @@ -10,6 +10,12 @@ public interface VpdPolicyMapper { List findPolicies(); + VpdPolicyView findPolicy( + @Param("objectOwner") String objectOwner, + @Param("objectName") String objectName, + @Param("policyName") String policyName + ); + String findFunctionSource( @Param("owner") String owner, @Param("objectName") String objectName, diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java b/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java index df06a24..51a7aae 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java @@ -1,6 +1,7 @@ package com.cloudhandson.vpdbackoffice.service; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdFunctionSource; +import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyDetail; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyView; import com.cloudhandson.vpdbackoffice.mapper.VpdPolicyMapper; import java.util.List; @@ -30,6 +31,72 @@ public class VpdPolicyService { return new VpdFunctionSource(normalizedOwner, objectName, objectType, source); } + public VpdPolicyDetail findPolicyDetail(String objectOwner, String objectName, String policyName) { + String normalizedOwner = requiredIdentifier(objectOwner, "Object owner"); + String normalizedObject = requiredIdentifier(objectName, "Object name"); + String normalizedPolicy = requiredIdentifier(policyName, "Policy name"); + VpdPolicyView policy = mapper.findPolicy(normalizedOwner, normalizedObject, normalizedPolicy); + if (policy == null) { + throw new AppException("VPD policy를 찾을 수 없습니다."); + } + return new VpdPolicyDetail(policy, buildAddPolicyBlock(policy)); + } + + private String buildAddPolicyBlock(VpdPolicyView policy) { + return """ + BEGIN + DBMS_RLS.ADD_POLICY( + object_schema => '%s', + object_name => '%s', + policy_name => '%s', + function_schema => '%s', + policy_function => '%s', + statement_types => '%s', + update_check => %s, + enable => %s, + static_policy => %s, + policy_type => %s, + long_predicate => %s + ); + END; + / + """.formatted( + policy.objectOwner(), + policy.objectName(), + policy.policyName(), + policy.functionOwner(), + policyFunctionArgument(policy), + blankToDefault(policy.statementTypes(), "SELECT"), + yesNoBoolean(policy.checkOption()), + yesNoBoolean(policy.enabled()), + yesNoBoolean(policy.staticPolicy()), + policyTypeArgument(policy.policyType()), + yesNoBoolean(policy.longPredicate()) + ); + } + + private String policyFunctionArgument(VpdPolicyView policy) { + if (policy.packageName() == null || policy.packageName().isBlank()) { + return policy.functionName(); + } + return policy.packageName() + "." + policy.functionName(); + } + + private String blankToDefault(String value, String defaultValue) { + return value == null || value.isBlank() ? defaultValue : value; + } + + private String yesNoBoolean(String value) { + return "YES".equalsIgnoreCase(value) ? "TRUE" : "FALSE"; + } + + private String policyTypeArgument(String policyType) { + if (policyType == null || policyType.isBlank()) { + return "NULL"; + } + return "DBMS_RLS." + policyType.trim().toUpperCase(Locale.ROOT); + } + private String requiredIdentifier(String value, String label) { String normalized = normalizeOptionalIdentifier(value); if (normalized == null) { diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java b/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java index 6369ad0..4bd374d 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java @@ -47,4 +47,22 @@ public class VpdPolicyController { } return "fragments/vpd-function-source :: source"; } + + @GetMapping("/vpd-policies/policy-detail") + public String policyDetail( + @RequestParam String objectOwner, + @RequestParam String objectName, + @RequestParam String policyName, + Model model + ) { + try { + model.addAttribute("detail", vpdPolicyService.findPolicyDetail(objectOwner, objectName, policyName)); + } catch (AppException exception) { + model.addAttribute("errorMessage", exception.getMessage()); + } catch (DataAccessException exception) { + RuntimeErrorMessage message = RuntimeErrorMessages.dataAccess(exception); + model.addAttribute("errorMessage", message.message()); + } + return "fragments/vpd-policy-detail :: detail"; + } } diff --git a/src/main/resources/mapper/VpdPolicyMapper.xml b/src/main/resources/mapper/VpdPolicyMapper.xml index e53df28..07b6a2d 100644 --- a/src/main/resources/mapper/VpdPolicyMapper.xml +++ b/src/main/resources/mapper/VpdPolicyMapper.xml @@ -2,32 +2,43 @@ + + object_owner, + object_name, + policy_group, + policy_name, + pf_owner AS function_owner, + package AS package_name, + function AS function_name, + RTRIM( + CASE WHEN sel = 'YES' THEN 'SELECT,' ELSE '' END || + CASE WHEN ins = 'YES' THEN 'INSERT,' ELSE '' END || + CASE WHEN upd = 'YES' THEN 'UPDATE,' ELSE '' END || + CASE WHEN del = 'YES' THEN 'DELETE,' ELSE '' END || + CASE WHEN idx = 'YES' THEN 'INDEX,' ELSE '' END, + ',' + ) AS statement_types, + chk_option AS check_option, + enable AS enabled, + static_policy, + policy_type, + long_predicate + + + +