fix #477: show target policy filters
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
package com.cloudhandson.vpdbackoffice.domain.vpd;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record VpdObjectFilterDetail(
|
||||||
|
String objectOwner,
|
||||||
|
String objectName,
|
||||||
|
List<Row> rows
|
||||||
|
) {
|
||||||
|
|
||||||
|
public String objectDisplayName() {
|
||||||
|
return objectOwner + "." + objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Row(
|
||||||
|
VpdPolicyView policy,
|
||||||
|
VpdFunctionSource source
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@ public record VpdTargetView(
|
|||||||
String protectedYn,
|
String protectedYn,
|
||||||
String ordsPath,
|
String ordsPath,
|
||||||
int policyCount,
|
int policyCount,
|
||||||
String policyNames
|
String policyNames,
|
||||||
|
String filterNames
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public String objectDisplayName() {
|
public String objectDisplayName() {
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ public interface VpdPolicyMapper {
|
|||||||
@Param("policyName") String policyName
|
@Param("policyName") String policyName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
List<VpdPolicyView> findPoliciesForObject(
|
||||||
|
@Param("objectOwner") String objectOwner,
|
||||||
|
@Param("objectName") String objectName
|
||||||
|
);
|
||||||
|
|
||||||
VpdPolicyView findAnyPolicy(
|
VpdPolicyView findAnyPolicy(
|
||||||
@Param("objectOwner") String objectOwner,
|
@Param("objectOwner") String objectOwner,
|
||||||
@Param("objectName") String objectName,
|
@Param("objectName") String objectName,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.cloudhandson.vpdbackoffice.service;
|
|||||||
|
|
||||||
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdBulkApplyResult;
|
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdBulkApplyResult;
|
||||||
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdFunctionSource;
|
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdFunctionSource;
|
||||||
|
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdObjectFilterDetail;
|
||||||
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyCreateCommand;
|
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyCreateCommand;
|
||||||
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyDetail;
|
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyDetail;
|
||||||
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyExplanation;
|
import com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyExplanation;
|
||||||
@@ -233,6 +234,18 @@ public class VpdPolicyService {
|
|||||||
return new VpdPolicyDetail(policy, buildAddPolicyBlock(policy));
|
return new VpdPolicyDetail(policy, buildAddPolicyBlock(policy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VpdObjectFilterDetail findObjectFilterDetail(String objectOwner, String objectName) {
|
||||||
|
String normalizedOwner = requiredIdentifier(objectOwner, "Object owner");
|
||||||
|
String normalizedObject = requiredIdentifier(objectName, "Object name");
|
||||||
|
List<VpdObjectFilterDetail.Row> rows = mapper.findPoliciesForObject(normalizedOwner, normalizedObject).stream()
|
||||||
|
.map(policy -> new VpdObjectFilterDetail.Row(
|
||||||
|
policy,
|
||||||
|
findFunctionSource(policy.functionOwner(), policy.packageName(), policy.functionName())
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
return new VpdObjectFilterDetail(normalizedOwner, normalizedObject, rows);
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void createPolicy(VpdPolicyCreateCommand command) {
|
public void createPolicy(VpdPolicyCreateCommand command) {
|
||||||
String objectOwner = requiredIdentifier(command.objectOwner(), "Object owner");
|
String objectOwner = requiredIdentifier(command.objectOwner(), "Object owner");
|
||||||
|
|||||||
@@ -306,6 +306,23 @@ public class VpdPolicyController {
|
|||||||
return "fragments/vpd-policy-detail :: detail";
|
return "fragments/vpd-policy-detail :: detail";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/vpd-policies/object-filter-detail")
|
||||||
|
public String objectFilterDetail(
|
||||||
|
@RequestParam String objectOwner,
|
||||||
|
@RequestParam String objectName,
|
||||||
|
Model model
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
model.addAttribute("detail", vpdPolicyService.findObjectFilterDetail(objectOwner, objectName));
|
||||||
|
} catch (AppException exception) {
|
||||||
|
model.addAttribute("errorMessage", exception.getMessage());
|
||||||
|
} catch (DataAccessException exception) {
|
||||||
|
RuntimeErrorMessage message = RuntimeErrorMessages.dataAccess(exception);
|
||||||
|
model.addAttribute("errorMessage", message.message());
|
||||||
|
}
|
||||||
|
return "fragments/vpd-object-filter-detail :: detail";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/vpd-policies/policy-explanation")
|
@GetMapping("/vpd-policies/policy-explanation")
|
||||||
public String policyExplanation(
|
public String policyExplanation(
|
||||||
@RequestParam String objectOwner,
|
@RequestParam String objectOwner,
|
||||||
|
|||||||
@@ -63,7 +63,13 @@
|
|||||||
CASE WHEN po.object_id IS NULL THEN 'N' ELSE po.enabled_yn END AS protected_yn,
|
CASE WHEN po.object_id IS NULL THEN 'N' ELSE po.enabled_yn END AS protected_yn,
|
||||||
po.ords_path,
|
po.ords_path,
|
||||||
COUNT(p.policy_name) AS policy_count,
|
COUNT(p.policy_name) AS policy_count,
|
||||||
LISTAGG(p.policy_name, ', ') WITHIN GROUP (ORDER BY p.policy_name) AS policy_names
|
LISTAGG(p.policy_name, ', ') WITHIN GROUP (ORDER BY p.policy_name) AS policy_names,
|
||||||
|
LISTAGG(
|
||||||
|
p.pf_owner ||
|
||||||
|
CASE WHEN p.package IS NULL THEN '.' ELSE '.' || p.package || '.' END ||
|
||||||
|
p.function,
|
||||||
|
', '
|
||||||
|
) WITHIN GROUP (ORDER BY p.policy_name) AS filter_names
|
||||||
FROM managed_objects o
|
FROM managed_objects o
|
||||||
LEFT JOIN cb_protected_object po
|
LEFT JOIN cb_protected_object po
|
||||||
ON po.owner = o.owner
|
ON po.owner = o.owner
|
||||||
@@ -210,6 +216,14 @@
|
|||||||
)
|
)
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="findPoliciesForObject" resultType="com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyView">
|
||||||
|
SELECT <include refid="policyColumns"><property name="alias" value="p."/></include>
|
||||||
|
FROM all_policies p
|
||||||
|
WHERE p.object_owner = UPPER(#{objectOwner,jdbcType=VARCHAR})
|
||||||
|
AND p.object_name = UPPER(#{objectName,jdbcType=VARCHAR})
|
||||||
|
ORDER BY p.policy_name
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="findAnyPolicy" resultType="com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyView">
|
<select id="findAnyPolicy" resultType="com.cloudhandson.vpdbackoffice.domain.vpd.VpdPolicyView">
|
||||||
SELECT <include refid="policyColumns"><property name="alias" value="p."/></include>
|
SELECT <include refid="policyColumns"><property name="alias" value="p."/></include>
|
||||||
FROM all_policies p
|
FROM all_policies p
|
||||||
|
|||||||
@@ -870,6 +870,12 @@ body {
|
|||||||
padding: .75rem;
|
padding: .75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-detail-stack + .filter-detail-stack {
|
||||||
|
border-top: 1px solid var(--rw-border);
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.policy-detail-list {
|
.policy-detail-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(120px, 34%) 1fr;
|
grid-template-columns: minmax(120px, 34%) 1fr;
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<body>
|
||||||
|
<div th:fragment="detail">
|
||||||
|
<div class="alert alert-warning mb-0" th:if="${errorMessage}" th:text="${errorMessage}"></div>
|
||||||
|
<section class="probe-exchange" th:if="${detail}">
|
||||||
|
<h3>
|
||||||
|
<span th:text="${detail.objectDisplayName()}">ADMIN.TABLE</span>
|
||||||
|
<span class="text-muted"> / Policy Filter</span>
|
||||||
|
</h3>
|
||||||
|
<div th:if="${#lists.isEmpty(detail.rows())}" class="text-muted">
|
||||||
|
이 TABLE/VIEW에 적용된 VPD policy/filter가 없습니다.
|
||||||
|
</div>
|
||||||
|
<div class="filter-detail-stack" th:each="row : ${detail.rows()}">
|
||||||
|
<dl class="policy-detail-list">
|
||||||
|
<dt>Policy</dt>
|
||||||
|
<dd><code th:text="${row.policy().policyName()}">POLICY</code></dd>
|
||||||
|
<dt>Filter</dt>
|
||||||
|
<dd><code th:text="${row.policy().functionDisplayName()}">ADMIN.FILTER</code></dd>
|
||||||
|
<dt>Statements</dt>
|
||||||
|
<dd th:text="${row.policy().statementTypes()} ?: '-'">SELECT</dd>
|
||||||
|
<dt>Status</dt>
|
||||||
|
<dd th:text="${row.policy().enabled()}">YES</dd>
|
||||||
|
</dl>
|
||||||
|
<pre th:if="${row.source().found()}" th:text="${row.source().source()}"></pre>
|
||||||
|
<pre th:unless="${row.source().found()}">ALL_SOURCE에서 조회 가능한 filter source가 없습니다.</pre>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -54,12 +54,14 @@
|
|||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>VPD 상태</th>
|
<th>VPD 상태</th>
|
||||||
<th>Policy</th>
|
<th>Policy</th>
|
||||||
|
<th>Filter</th>
|
||||||
<th>백오피스 권한 테이블</th>
|
<th>백오피스 권한 테이블</th>
|
||||||
<th>ORDS Path</th>
|
<th>ORDS Path</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="target : ${vpdTargets}">
|
<th:block th:each="target, iter : ${vpdTargets}">
|
||||||
|
<tr>
|
||||||
<td><code th:text="${target.objectDisplayName()}">ADMIN.TABLE</code></td>
|
<td><code th:text="${target.objectDisplayName()}">ADMIN.TABLE</code></td>
|
||||||
<td th:text="${target.objectType()}">TABLE</td>
|
<td th:text="${target.objectType()}">TABLE</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -71,6 +73,17 @@
|
|||||||
<span th:if="${target.vpdApplied()}" th:text="${target.policyNames()}">POLICY</span>
|
<span th:if="${target.vpdApplied()}" th:text="${target.policyNames()}">POLICY</span>
|
||||||
<span th:unless="${target.vpdApplied()}" class="text-muted">-</span>
|
<span th:unless="${target.vpdApplied()}" class="text-muted">-</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<button th:if="${target.vpdApplied()}"
|
||||||
|
class="btn btn-sm btn-outline-secondary policy-function-button"
|
||||||
|
type="button"
|
||||||
|
th:hx-get="@{/vpd-policies/object-filter-detail(objectOwner=${target.owner()},objectName=${target.objectName()})}"
|
||||||
|
th:hx-target="${'#target-filter-detail-' + iter.index}"
|
||||||
|
hx-swap="innerHTML">
|
||||||
|
<code th:text="${target.filterNames()}">ADMIN.FILTER</code>
|
||||||
|
</button>
|
||||||
|
<span th:unless="${target.vpdApplied()}" class="text-muted">-</span>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge"
|
<span class="badge"
|
||||||
th:classappend="${target.protectedObject()} ? ' text-bg-primary' : ' text-bg-light'"
|
th:classappend="${target.protectedObject()} ? ' text-bg-primary' : ' text-bg-light'"
|
||||||
@@ -81,8 +94,16 @@
|
|||||||
<span th:unless="${target.ordsPath()}" class="text-muted">ORDS 서빙 미등록</span>
|
<span th:unless="${target.ordsPath()}" class="text-muted">ORDS 서빙 미등록</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr th:if="${target.vpdApplied()}">
|
||||||
|
<td colspan="7" class="policy-source-cell">
|
||||||
|
<div th:id="${'target-filter-detail-' + iter.index}" class="text-muted small">
|
||||||
|
Filter 이름을 클릭하면 policy/filter source가 표시됩니다.
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</th:block>
|
||||||
<tr th:if="${#lists.isEmpty(vpdTargets)}">
|
<tr th:if="${#lists.isEmpty(vpdTargets)}">
|
||||||
<td colspan="6" class="text-muted">
|
<td colspan="7" class="text-muted">
|
||||||
<span th:if="${selectedSchemaOwner != null && selectedSchemaOwner != ''}"
|
<span th:if="${selectedSchemaOwner != null && selectedSchemaOwner != ''}"
|
||||||
th:text="${selectedSchemaOwner + ' 스키마에서 현재 DB 연결 사용자로 조회 가능한 TABLE/VIEW가 없습니다. 스키마명, ALL_OBJECTS 조회 권한, 객체 권한을 확인하세요.'}">
|
th:text="${selectedSchemaOwner + ' 스키마에서 현재 DB 연결 사용자로 조회 가능한 TABLE/VIEW가 없습니다. 스키마명, ALL_OBJECTS 조회 권한, 객체 권한을 확인하세요.'}">
|
||||||
선택한 스키마에서 조회 가능한 TABLE/VIEW가 없습니다.
|
선택한 스키마에서 조회 가능한 TABLE/VIEW가 없습니다.
|
||||||
|
|||||||
Reference in New Issue
Block a user