EventType 화면 고정 제외 코드 필터링 로직 추가
- 제외 코드(CHECK_NOTICE 등) 구독 방지 위한 유효성 검사 강화 - 선택 가능한 EventType만 검증/표시하도록 로직 수정
This commit is contained in:
@@ -113,3 +113,4 @@ diff
|
|||||||
*gf63*
|
*gf63*
|
||||||
*obsidian*
|
*obsidian*
|
||||||
design-backup
|
design-backup
|
||||||
|
/.envrc
|
||||||
|
|||||||
@@ -210,8 +210,11 @@ public class WebhookController {
|
|||||||
modification.setId(webhook.getId());
|
modification.setId(webhook.getId());
|
||||||
modification.setRequestType("MODIFY");
|
modification.setRequestType("MODIFY");
|
||||||
modification.setTargetUrl(webhook.getTargetUrl());
|
modification.setTargetUrl(webhook.getTargetUrl());
|
||||||
|
// 화면 고정 제외 코드(CHECK_NOTICE 등)는 체크박스가 렌더링되지 않으므로 세션 값에서도 제외한다.
|
||||||
modification.setEventTypes(webhook.getEventTypes().stream()
|
modification.setEventTypes(webhook.getEventTypes().stream()
|
||||||
.map(e -> e.getCode()).collect(java.util.stream.Collectors.toList()));
|
.map(e -> e.getCode())
|
||||||
|
.filter(code -> !eventTypeProvider.isHidden(code))
|
||||||
|
.collect(java.util.stream.Collectors.toList()));
|
||||||
modification.setSelectedApis(new java.util.ArrayList<>(webhook.getApiIds()));
|
modification.setSelectedApis(new java.util.ArrayList<>(webhook.getApiIds()));
|
||||||
model.addAttribute("webhookModification", modification);
|
model.addAttribute("webhookModification", modification);
|
||||||
}
|
}
|
||||||
@@ -374,7 +377,9 @@ public class WebhookController {
|
|||||||
bindingResult.rejectValue("targetUrl", "invalid.url",
|
bindingResult.rejectValue("targetUrl", "invalid.url",
|
||||||
"올바른 URL 형식이 아닙니다. http:// 또는 https:// 로 시작하는 전체 주소를 입력해주세요.");
|
"올바른 URL 형식이 아닙니다. http:// 또는 https:// 로 시작하는 전체 주소를 입력해주세요.");
|
||||||
}
|
}
|
||||||
if (dto.getEventTypes() == null || dto.getEventTypes().isEmpty()) {
|
boolean hasSelectableEventType = dto.getEventTypes() != null && dto.getEventTypes().stream()
|
||||||
|
.anyMatch(code -> !eventTypeProvider.isHidden(code));
|
||||||
|
if (!hasSelectableEventType) {
|
||||||
bindingResult.rejectValue("eventTypes", "empty.eventTypes",
|
bindingResult.rejectValue("eventTypes", "empty.eventTypes",
|
||||||
"EventType을 1개 이상 선택해주세요.");
|
"EventType을 1개 이상 선택해주세요.");
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-1
@@ -2,9 +2,13 @@ package com.eactive.apim.portal.djb.webhook.service;
|
|||||||
|
|
||||||
import com.eactive.apim.portal.djb.webhook.dto.WebhookEventTypeDTO;
|
import com.eactive.apim.portal.djb.webhook.dto.WebhookEventTypeDTO;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -20,6 +24,14 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
@Component
|
@Component
|
||||||
public class WebhookEventTypeProvider {
|
public class WebhookEventTypeProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 신청/수정 화면의 선택 목록에서 고정으로 제외하는 EventType 코드.
|
||||||
|
* DB(TSEAIRM28)에 USEYN='Y' 로 남아 있어도 포털 사용자가 직접 구독할 수 없는 코드다.
|
||||||
|
* 기존 데이터 표시(이름 조회)에는 영향이 없다.
|
||||||
|
*/
|
||||||
|
private static final Set<String> HIDDEN_CODES =
|
||||||
|
Collections.unmodifiableSet(new HashSet<>(Arrays.asList("CHECK_NOTICE")));
|
||||||
|
|
||||||
private static final String EVENT_TYPE_SQL =
|
private static final String EVENT_TYPE_SQL =
|
||||||
"SELECT CODE, CODENAME FROM TSEAIRM28 "
|
"SELECT CODE, CODENAME FROM TSEAIRM28 "
|
||||||
+ "WHERE CODEGROUP = 'EVENT_TYPE' AND USEYN = 'Y' "
|
+ "WHERE CODEGROUP = 'EVENT_TYPE' AND USEYN = 'Y' "
|
||||||
@@ -29,15 +41,25 @@ public class WebhookEventTypeProvider {
|
|||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
|
|
||||||
|
/** 신청/수정 화면에 노출할 선택 가능한 EventType 목록({@link #HIDDEN_CODES} 제외). */
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public List<WebhookEventTypeDTO> getAll() {
|
public List<WebhookEventTypeDTO> getAll() {
|
||||||
List<WebhookEventTypeDTO> list = new ArrayList<>();
|
List<WebhookEventTypeDTO> list = new ArrayList<>();
|
||||||
for (Object[] row : rows()) {
|
for (Object[] row : rows()) {
|
||||||
list.add(new WebhookEventTypeDTO(asString(row[0]), asString(row[1])));
|
String code = asString(row[0]);
|
||||||
|
if (isHidden(code)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list.add(new WebhookEventTypeDTO(code, asString(row[1])));
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 화면 노출/구독 대상에서 고정 제외되는 코드인지 여부. */
|
||||||
|
public boolean isHidden(String code) {
|
||||||
|
return code != null && HIDDEN_CODES.contains(code);
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Map<String, String> asMap() {
|
public Map<String, String> asMap() {
|
||||||
Map<String, String> map = new LinkedHashMap<>();
|
Map<String, String> map = new LinkedHashMap<>();
|
||||||
@@ -47,6 +69,7 @@ public class WebhookEventTypeProvider {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 코드 자체의 유효성(제외 코드 포함). 구독 가능 여부는 {@link #isHidden(String)} 로 별도 판단한다. */
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public boolean isValid(String code) {
|
public boolean isValid(String code) {
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ public class WebhookService {
|
|||||||
for (String apiId : dedup(dto.getSelectedApis())) {
|
for (String apiId : dedup(dto.getSelectedApis())) {
|
||||||
apiRepository.save(new WebhookRequestApi(reqId, apiId));
|
apiRepository.save(new WebhookRequestApi(reqId, apiId));
|
||||||
}
|
}
|
||||||
for (String eventType : dedup(dto.getEventTypes())) {
|
for (String eventType : selectableEventTypes(dto)) {
|
||||||
if (!eventTypeProvider.isValid(eventType)) {
|
if (!eventTypeProvider.isValid(eventType)) {
|
||||||
throw new IllegalArgumentException("유효하지 않은 EventType 코드입니다: " + eventType);
|
throw new IllegalArgumentException("유효하지 않은 EventType 코드입니다: " + eventType);
|
||||||
}
|
}
|
||||||
@@ -169,11 +169,22 @@ public class WebhookService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 중복 제거 + 화면 고정 제외 코드(예: CHECK_NOTICE) 제거.
|
||||||
|
* 제외 코드는 신청/수정 화면에 체크박스가 렌더링되지 않으므로 정상 경로로는 들어오지 않지만,
|
||||||
|
* 세션에 남은 값이나 직접 조작한 요청으로 구독되지 않도록 저장 직전에 한 번 더 걸러낸다.
|
||||||
|
*/
|
||||||
|
private List<String> selectableEventTypes(WebhookRegistrationDTO dto) {
|
||||||
|
return dedup(dto.getEventTypes()).stream()
|
||||||
|
.filter(code -> !eventTypeProvider.isHidden(code))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
private void validate(WebhookRegistrationDTO dto) {
|
private void validate(WebhookRegistrationDTO dto) {
|
||||||
if (!WebhookUrlValidator.isValid(dto.getTargetUrl())) {
|
if (!WebhookUrlValidator.isValid(dto.getTargetUrl())) {
|
||||||
throw new IllegalArgumentException("올바른 URL 형식이 아닙니다. http:// 또는 https:// 로 시작하는 전체 주소를 입력해주세요.");
|
throw new IllegalArgumentException("올바른 URL 형식이 아닙니다. http:// 또는 https:// 로 시작하는 전체 주소를 입력해주세요.");
|
||||||
}
|
}
|
||||||
if (dto.getEventTypes() == null || dto.getEventTypes().isEmpty()) {
|
if (selectableEventTypes(dto).isEmpty()) {
|
||||||
throw new IllegalArgumentException("EventType을 1개 이상 선택해주세요.");
|
throw new IllegalArgumentException("EventType을 1개 이상 선택해주세요.");
|
||||||
}
|
}
|
||||||
if (dto.getSelectedApis() == null || dto.getSelectedApis().isEmpty()) {
|
if (dto.getSelectedApis() == null || dto.getSelectedApis().isEmpty()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user