diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java new file mode 100644 index 0000000..c098bfc --- /dev/null +++ b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java @@ -0,0 +1,18 @@ +package com.cloudhandson.vpdbackoffice.domain.vpd; + +public record VpdFunctionOption( + String owner, + String packageName, + String functionName, + String objectType +) { + + public String value() { + String packagePrefix = packageName == null || packageName.isBlank() ? "" : packageName + "."; + return owner + "." + packagePrefix + functionName; + } + + public String label() { + return value() + " / " + objectType; + } +} diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java index b276011..0e09f36 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java @@ -4,6 +4,7 @@ public record VpdPolicyCreateCommand( String objectOwner, String objectName, String policyName, + String functionKey, String functionOwner, String functionName, String statementTypes, diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java new file mode 100644 index 0000000..0a5661b --- /dev/null +++ b/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java @@ -0,0 +1,11 @@ +package com.cloudhandson.vpdbackoffice.domain.vpd; + +import java.util.List; + +public record VpdPolicyFormOptions( + List policyNames, + List owners, + List functions, + List statementTypes +) { +} diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java b/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java index c432f3f..04aad37 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java @@ -1,5 +1,6 @@ package com.cloudhandson.vpdbackoffice.mapper; +import com.cloudhandson.vpdbackoffice.domain.vpd.VpdFunctionOption; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyView; import java.util.List; import org.apache.ibatis.annotations.Mapper; @@ -10,6 +11,12 @@ public interface VpdPolicyMapper { List findPolicies(); + List findPolicyNameOptions(); + + List findOwnerOptions(); + + List findFunctionOptions(); + VpdPolicyView findPolicy( @Param("objectOwner") String objectOwner, @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 5ecc83e..31035e0 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java @@ -4,6 +4,7 @@ import com.cloudhandson.vpdbackoffice.domain.vpd.VpdFunctionSource; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyCreateCommand; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyDetail; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyExplanation; +import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyFormOptions; import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyView; import com.cloudhandson.vpdbackoffice.mapper.VpdPolicyMapper; import java.util.List; @@ -32,6 +33,24 @@ public class VpdPolicyService { return mapper.findPolicies(); } + public VpdPolicyFormOptions formOptions() { + return new VpdPolicyFormOptions( + mapper.findPolicyNameOptions(), + mapper.findOwnerOptions(), + mapper.findFunctionOptions(), + List.of("SELECT", "INSERT", "UPDATE", "DELETE", "INDEX") + ); + } + + public VpdPolicyFormOptions emptyFormOptions() { + return new VpdPolicyFormOptions( + List.of(), + List.of(), + List.of(), + List.of("SELECT", "INSERT", "UPDATE", "DELETE", "INDEX") + ); + } + public VpdFunctionSource findFunctionSource(String owner, String packageName, String functionName) { String normalizedOwner = requiredIdentifier(owner, "Function owner"); String normalizedFunction = requiredIdentifier(functionName, "Function name"); @@ -59,12 +78,23 @@ public class VpdPolicyService { String objectName = requiredIdentifier(command.objectName(), "Object name"); String policyName = requiredIdentifier(command.policyName(), "Policy name"); String currentUser = jdbcTemplate.queryForObject("SELECT USER FROM dual", String.class); - String functionOwner = command.functionOwner() == null || command.functionOwner().isBlank() - ? currentUser - : requiredIdentifier(command.functionOwner(), "Function owner"); - String functionName = command.functionName() == null || command.functionName().isBlank() - ? generatedFunctionName(policyName) - : requiredIdentifier(command.functionName(), "Function name"); + FunctionRef functionRef = parseFunctionRef(command.functionKey()); + String functionOwner; + String packageName; + String functionName; + if (functionRef != null) { + functionOwner = functionRef.owner(); + packageName = functionRef.packageName(); + functionName = functionRef.functionName(); + } else { + functionOwner = command.functionOwner() == null || command.functionOwner().isBlank() + ? currentUser + : requiredIdentifier(command.functionOwner(), "Function owner"); + packageName = null; + functionName = command.functionName() == null || command.functionName().isBlank() + ? generatedFunctionName(policyName) + : requiredIdentifier(command.functionName(), "Function name"); + } String statementTypes = normalizeStatementTypes(command.statementTypes()); String filterPredicate = command.filterPredicate() == null ? "" : command.filterPredicate().trim(); @@ -95,7 +125,7 @@ public class VpdPolicyService { objectName, policyName, functionOwner, - functionName, + packageName == null ? functionName : packageName + "." + functionName, statementTypes); } @@ -271,6 +301,22 @@ public class VpdPolicyService { return generated.length() > 128 ? generated.substring(0, 128) : generated; } + private FunctionRef parseFunctionRef(String functionKey) { + if (functionKey == null || functionKey.isBlank()) { + return null; + } + String[] parts = functionKey.trim().toUpperCase(Locale.ROOT).split("\\."); + if (parts.length == 2) { + return new FunctionRef(requiredIdentifier(parts[0], "Function owner"), null, + requiredIdentifier(parts[1], "Function name")); + } + if (parts.length == 3) { + return new FunctionRef(requiredIdentifier(parts[0], "Function owner"), + requiredIdentifier(parts[1], "Package name"), requiredIdentifier(parts[2], "Function name")); + } + throw new AppException("Function 선택 값이 올바르지 않습니다: " + functionKey); + } + private String normalizeStatementTypes(String value) { String raw = value == null || value.isBlank() ? "SELECT" : value; List statements = List.of(raw.split(",")).stream() @@ -293,6 +339,9 @@ public class VpdPolicyService { return value.replace("'", "''"); } + private record FunctionRef(String owner, String packageName, String functionName) { + } + private String policyFunctionArgument(VpdPolicyView policy) { if (policy.packageName() == null || policy.packageName().isBlank()) { return policy.functionName(); diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java b/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java index 339bcc5..e702da5 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java @@ -29,11 +29,13 @@ public class VpdPolicyController { try { model.addAttribute("policies", vpdPolicyService.findPolicies()); model.addAttribute("objects", protectedObjectService.findEnabled()); + model.addAttribute("formOptions", vpdPolicyService.formOptions()); } catch (DataAccessException exception) { RuntimeErrorMessage message = RuntimeErrorMessages.dataAccess(exception); model.addAttribute("runtimeError", message); model.addAttribute("policies", List.of()); model.addAttribute("objects", List.of()); + model.addAttribute("formOptions", vpdPolicyService.emptyFormOptions()); } return "vpd-policies"; } @@ -42,9 +44,10 @@ public class VpdPolicyController { public String createPolicy( @RequestParam String objectKey, @RequestParam String policyName, + @RequestParam(required = false) String functionKey, @RequestParam(required = false) String functionOwner, @RequestParam(required = false) String functionName, - @RequestParam(defaultValue = "SELECT") String statementTypes, + @RequestParam(defaultValue = "SELECT") List statementTypes, @RequestParam(defaultValue = "false") boolean enabled, @RequestParam(defaultValue = "false") boolean updateCheck, @RequestParam(required = false) String filterPredicate, @@ -59,9 +62,10 @@ public class VpdPolicyController { objectParts[0], objectParts[1], policyName, + functionKey, functionOwner, functionName, - statementTypes, + String.join(",", statementTypes), enabled, updateCheck, filterPredicate diff --git a/src/main/resources/mapper/VpdPolicyMapper.xml b/src/main/resources/mapper/VpdPolicyMapper.xml index 0e49dfd..4708775 100644 --- a/src/main/resources/mapper/VpdPolicyMapper.xml +++ b/src/main/resources/mapper/VpdPolicyMapper.xml @@ -38,6 +38,47 @@ ORDER BY p.object_owner, p.object_name, p.policy_name + + + + + + + + + -