[Developer] #424 show VPD policy details

This commit is contained in:
devmrko
2026-06-25 11:18:22 +09:00
parent 86e2b252c9
commit 1c3894cb40
7 changed files with 167 additions and 23 deletions

View File

@@ -0,0 +1,7 @@
package com.cloudhandson.vpdbackoffice.domain.vpd;
public record VpdPolicyDetail(
VpdPolicyView policy,
String ddl
) {
}

View File

@@ -10,6 +10,12 @@ public interface VpdPolicyMapper {
List<VpdPolicyView> 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,

View File

@@ -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) {

View File

@@ -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";
}
}