[Developer] #424 stop guessing protected object ORDS paths
This commit is contained in:
@@ -13,8 +13,4 @@ public record DatabaseObjectOption(
|
|||||||
public String label() {
|
public String label() {
|
||||||
return owner + "." + objectName + " (" + objectType + ")";
|
return owner + "." + objectName + " (" + objectType + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String defaultOrdsPath() {
|
|
||||||
return owner.toLowerCase() + "/" + objectName.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,5 +34,7 @@ public interface ProtectedObjectMapper {
|
|||||||
@Param("columnName") String columnName,
|
@Param("columnName") String columnName,
|
||||||
@Param("sensitiveYn") String sensitiveYn);
|
@Param("sensitiveYn") String sensitiveYn);
|
||||||
|
|
||||||
|
int updateOrdsPath(@Param("objectId") long objectId, @Param("ordsPath") String ordsPath);
|
||||||
|
|
||||||
int disableObject(@Param("objectId") long objectId);
|
int disableObject(@Param("objectId") long objectId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,29 +68,8 @@ public class ProtectedObjectService {
|
|||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
List<String> columns = mapper.findDatabaseColumns(owner, objectName);
|
throw new AppException("테이블/뷰 관리에서 실제 ORDS Path를 먼저 등록하세요: "
|
||||||
if (columns.isEmpty()) {
|
+ owner.toUpperCase(Locale.ROOT) + "." + objectName.toUpperCase(Locale.ROOT));
|
||||||
throw new AppException("DB 객체 컬럼을 찾을 수 없습니다: " + owner + "." + objectName);
|
|
||||||
}
|
|
||||||
long objectId = mapper.nextObjectId();
|
|
||||||
mapper.insertObject(objectId, new ProtectedObjectCreateCommand(
|
|
||||||
owner,
|
|
||||||
objectName,
|
|
||||||
defaultOrdsPath(owner, objectName),
|
|
||||||
String.join(",", columns),
|
|
||||||
""
|
|
||||||
));
|
|
||||||
for (String column : columns) {
|
|
||||||
mapper.insertColumn(mapper.nextColumnId(), objectId, column, "N");
|
|
||||||
}
|
|
||||||
auditService.record(new AuditEvent("PROTECTED_OBJECT_CREATED", null, objectId, "SUCCESS", null, null,
|
|
||||||
owner + "." + objectName));
|
|
||||||
return mapper.findById(objectId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String defaultOrdsPath(String owner, String objectName) {
|
|
||||||
String schemaPath = owner.equalsIgnoreCase("CB_ORDS") ? "cb-ords" : owner.toLowerCase(Locale.ROOT);
|
|
||||||
return schemaPath + "/" + objectName.toLowerCase(Locale.ROOT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProtectedObjectCreateCommand normalizeCreateCommand(ProtectedObjectCreateCommand command) {
|
private ProtectedObjectCreateCommand normalizeCreateCommand(ProtectedObjectCreateCommand command) {
|
||||||
@@ -98,7 +77,7 @@ public class ProtectedObjectService {
|
|||||||
String objectName = command.objectName().trim().toUpperCase(Locale.ROOT);
|
String objectName = command.objectName().trim().toUpperCase(Locale.ROOT);
|
||||||
String ordsPath = command.ordsPath();
|
String ordsPath = command.ordsPath();
|
||||||
if (ordsPath == null || ordsPath.isBlank()) {
|
if (ordsPath == null || ordsPath.isBlank()) {
|
||||||
ordsPath = defaultOrdsPath(owner, objectName);
|
throw new AppException("ORDS Path는 실제 ORDS module/template 경로를 입력해야 합니다.");
|
||||||
}
|
}
|
||||||
String columns = command.columns();
|
String columns = command.columns();
|
||||||
if (columns == null || columns.isBlank()) {
|
if (columns == null || columns.isBlank()) {
|
||||||
@@ -107,6 +86,19 @@ public class ProtectedObjectService {
|
|||||||
return new ProtectedObjectCreateCommand(owner, objectName, ordsPath.trim(), columns, command.sensitiveColumns());
|
return new ProtectedObjectCreateCommand(owner, objectName, ordsPath.trim(), columns, command.sensitiveColumns());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void updateOrdsPath(long objectId, String ordsPath) {
|
||||||
|
if (ordsPath == null || ordsPath.isBlank()) {
|
||||||
|
throw new AppException("ORDS Path는 필수입니다.");
|
||||||
|
}
|
||||||
|
int updated = mapper.updateOrdsPath(objectId, ordsPath.trim());
|
||||||
|
if (updated == 0) {
|
||||||
|
throw new AppException("보호 객체를 찾을 수 없습니다.");
|
||||||
|
}
|
||||||
|
auditService.record(new AuditEvent("PROTECTED_OBJECT_ORDS_PATH_UPDATED", null, objectId, "SUCCESS", null, null,
|
||||||
|
ordsPath.trim()));
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void disableObject(long objectId) {
|
public void disableObject(long objectId) {
|
||||||
int updated = mapper.disableObject(objectId);
|
int updated = mapper.disableObject(objectId);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.cloudhandson.vpdbackoffice.web;
|
package com.cloudhandson.vpdbackoffice.web;
|
||||||
|
|
||||||
import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedObjectCreateCommand;
|
import com.cloudhandson.vpdbackoffice.domain.protectedobject.ProtectedObjectCreateCommand;
|
||||||
|
import com.cloudhandson.vpdbackoffice.service.AppException;
|
||||||
import com.cloudhandson.vpdbackoffice.service.ProtectedObjectService;
|
import com.cloudhandson.vpdbackoffice.service.ProtectedObjectService;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
@@ -34,9 +35,28 @@ public class ProtectedObjectController {
|
|||||||
@RequestParam(required = false) String sensitiveColumns,
|
@RequestParam(required = false) String sensitiveColumns,
|
||||||
RedirectAttributes redirectAttributes
|
RedirectAttributes redirectAttributes
|
||||||
) {
|
) {
|
||||||
|
try {
|
||||||
protectedObjectService.createObject(
|
protectedObjectService.createObject(
|
||||||
new ProtectedObjectCreateCommand(owner, objectName, ordsPath, columns, sensitiveColumns));
|
new ProtectedObjectCreateCommand(owner, objectName, ordsPath, columns, sensitiveColumns));
|
||||||
redirectAttributes.addFlashAttribute("message", "보호 객체를 추가했습니다.");
|
redirectAttributes.addFlashAttribute("message", "보호 객체를 추가했습니다.");
|
||||||
|
} catch (AppException exception) {
|
||||||
|
redirectAttributes.addFlashAttribute("errorMessage", exception.getMessage());
|
||||||
|
}
|
||||||
|
return "redirect:/objects";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/objects/ords-path")
|
||||||
|
public String updateOrdsPath(
|
||||||
|
@RequestParam long objectId,
|
||||||
|
@RequestParam String ordsPath,
|
||||||
|
RedirectAttributes redirectAttributes
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
protectedObjectService.updateOrdsPath(objectId, ordsPath);
|
||||||
|
redirectAttributes.addFlashAttribute("message", "ORDS Path를 수정했습니다.");
|
||||||
|
} catch (AppException exception) {
|
||||||
|
redirectAttributes.addFlashAttribute("errorMessage", exception.getMessage());
|
||||||
|
}
|
||||||
return "redirect:/objects";
|
return "redirect:/objects";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,12 @@
|
|||||||
VALUES (#{columnId}, #{objectId}, UPPER(#{columnName}), #{sensitiveYn})
|
VALUES (#{columnId}, #{objectId}, UPPER(#{columnName}), #{sensitiveYn})
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateOrdsPath">
|
||||||
|
UPDATE cb_protected_object
|
||||||
|
SET ords_path = #{ordsPath,jdbcType=VARCHAR}
|
||||||
|
WHERE object_id = #{objectId,jdbcType=NUMERIC}
|
||||||
|
</update>
|
||||||
|
|
||||||
<update id="disableObject">
|
<update id="disableObject">
|
||||||
UPDATE cb_protected_object
|
UPDATE cb_protected_object
|
||||||
SET enabled_yn = 'N'
|
SET enabled_yn = 'N'
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ async function syncObjectCatalogSelection() {
|
|||||||
if (objectInput) {
|
if (objectInput) {
|
||||||
objectInput.value = selected.dataset.objectName || '';
|
objectInput.value = selected.dataset.objectName || '';
|
||||||
}
|
}
|
||||||
if (ordsPathInput) {
|
if (ordsPathInput && !ordsPathInput.value) {
|
||||||
ordsPathInput.value = selected.dataset.defaultPath || '';
|
ordsPathInput.focus();
|
||||||
}
|
}
|
||||||
if (!columnsInput) {
|
if (!columnsInput) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-success" th:if="${message}" th:text="${message}"></div>
|
<div class="alert alert-success" th:if="${message}" th:text="${message}"></div>
|
||||||
|
<div class="alert alert-danger" th:if="${errorMessage}" th:text="${errorMessage}"></div>
|
||||||
|
|
||||||
<section class="content-band">
|
<section class="content-band">
|
||||||
<h2>테이블/뷰 추가</h2>
|
<h2>테이블/뷰 추가</h2>
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
th:value="${dbObject.value()}"
|
th:value="${dbObject.value()}"
|
||||||
th:data-owner="${dbObject.owner()}"
|
th:data-owner="${dbObject.owner()}"
|
||||||
th:data-object-name="${dbObject.objectName()}"
|
th:data-object-name="${dbObject.objectName()}"
|
||||||
th:data-default-path="${dbObject.defaultOrdsPath()}"
|
|
||||||
th:text="${dbObject.label()}"></option>
|
th:text="${dbObject.label()}"></option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
ORDS Path
|
ORDS Path
|
||||||
<input class="form-control" name="ordsPath" placeholder="admin/cb_v_search_documents">
|
<input class="form-control" name="ordsPath" placeholder="cb-ords/cb-agent-security/vpd/documents" required>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
컬럼
|
컬럼
|
||||||
@@ -69,7 +69,14 @@
|
|||||||
<td th:text="${object.objectId()}">1</td>
|
<td th:text="${object.objectId()}">1</td>
|
||||||
<td th:text="${object.owner()}">ADMIN</td>
|
<td th:text="${object.owner()}">ADMIN</td>
|
||||||
<td th:text="${object.objectName()}">CB_V_SEARCH_DOCUMENTS</td>
|
<td th:text="${object.objectName()}">CB_V_SEARCH_DOCUMENTS</td>
|
||||||
<td><code th:text="${object.ordsPath()}">path</code></td>
|
<td>
|
||||||
|
<form method="post" action="/objects/ords-path" class="inline-form">
|
||||||
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||||
|
<input type="hidden" name="objectId" th:value="${object.objectId()}">
|
||||||
|
<input class="form-control form-control-sm" name="ordsPath" th:value="${object.ordsPath()}" required>
|
||||||
|
<button class="btn btn-sm btn-outline-primary" type="submit">저장</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<form method="post" action="/objects/disable" class="inline-form">
|
<form method="post" action="/objects/disable" class="inline-form">
|
||||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||||
|
|||||||
Reference in New Issue
Block a user