diff --git a/src/main/java/com/eactive/apim/portal/agreements/service/AgreementTypeConfigService.java b/src/main/java/com/eactive/apim/portal/agreements/service/AgreementTypeConfigService.java new file mode 100644 index 0000000..cdbe9db --- /dev/null +++ b/src/main/java/com/eactive/apim/portal/agreements/service/AgreementTypeConfigService.java @@ -0,0 +1,146 @@ +package com.eactive.apim.portal.agreements.service; + +import com.eactive.apim.portal.agreements.entity.AgreementType; +import com.eactive.apim.portal.portalproperty.service.PortalPropertyService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 약관 종류 운영 설정 조회. PTL_PROPERTY(그룹 {@code Portal})로 관리하며 admin·portal 이 같은 값을 본다. + * + * + * + * + * + * + * + *
PTL_PROPERTY (group = Portal)
{@code portal.terms.enabled-types}시스템에서 사용할 약관 종류. 쉼표 구분, 순서 무의미
{@code portal.terms.display-types}약관 페이지에 노출할 약관 종류. 쉼표 구분, 기재 순서가 노출 순서
+ * + *

값은 관리 콘솔의 '약관 목록 > 약관 종류 관리' 화면에서 설정한다. 프로퍼티가 없으면 + * {@link #DEFAULT_TYPES} 를 사용하며 조회만으로 행을 만들지는 않는다 + * (PTL_PROPERTY 는 (그룹, 이름) 유니크 제약이 없어 동시 요청이 중복 행을 만들 수 있다). + * 알 수 없는 코드는 무시하므로 enum 항목이 빠져도 화면이 깨지지 않는다. + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AgreementTypeConfigService { + + public static final String PROPERTY_GROUP = "Portal"; + public static final String ENABLED_TYPES_KEY = "portal.terms.enabled-types"; + public static final String DISPLAY_TYPES_KEY = "portal.terms.display-types"; + public static final String AGREE_ALL_ENABLED_KEY = "portal.terms.agree-all-enabled"; + + /** '전체 동의' 기본값 — 미설정 시 항목별로 끝까지 읽고 개별 동의하는 방식 */ + public static final boolean DEFAULT_AGREE_ALL_ENABLED = false; + + /** 프로퍼티 미설정 시 기본값 — 현재 운영중인 약관 종류 */ + public static final List DEFAULT_TYPES = Collections.unmodifiableList(Arrays.asList( + AgreementType.TERMS_OF_USE, + AgreementType.PRIVACY_COLLECT, + AgreementType.NOTIFICATION_CONSENT)); + + private final PortalPropertyService portalPropertyService; + + /** 시스템에서 사용하는 약관 종류 */ + public Set getEnabledTypes() { + Set enabled = EnumSet.noneOf(AgreementType.class); + enabled.addAll(readTypes(readGroupProperties(), ENABLED_TYPES_KEY)); + return enabled; + } + + /** 약관 페이지에 노출할 약관 종류(노출 순서대로). 사용하지 않는 종류는 제외된다. */ + public List getDisplayTypes() { + Map properties = readGroupProperties(); + List enabled = readTypes(properties, ENABLED_TYPES_KEY); + + List display = new ArrayList<>(); + for (AgreementType type : readTypes(properties, DISPLAY_TYPES_KEY)) { + if (enabled.contains(type)) { + display.add(type); + } + } + return display; + } + + /** 시스템에서 사용하는 약관 종류인지 여부 */ + public boolean isEnabled(AgreementType type) { + return getEnabledTypes().contains(type); + } + + /** 약관 페이지에 노출(배치)된 약관 종류인지 여부. 사용하지 않는 종류는 항상 {@code false}. */ + public boolean isDisplayed(AgreementType type) { + return getDisplayTypes().contains(type); + } + + /** + * 회원가입 약관 동의 화면에서 '전체 동의'를 허용할지 여부. + * + *

+ */ + public boolean isAgreeAllEnabled() { + return parseBoolean(readGroupProperties().get(AGREE_ALL_ENABLED_KEY)); + } + + /** {@code true/false} 외에 레거시 {@code Y/N}, {@code 1/0} 표기도 허용한다. */ + private boolean parseBoolean(String value) { + if (value == null || value.trim().isEmpty()) { + return DEFAULT_AGREE_ALL_ENABLED; + } + String trimmed = value.trim(); + if ("true".equalsIgnoreCase(trimmed) || "Y".equalsIgnoreCase(trimmed) || "1".equals(trimmed)) { + return true; + } + if ("false".equalsIgnoreCase(trimmed) || "N".equalsIgnoreCase(trimmed) || "0".equals(trimmed)) { + return false; + } + log.warn("PTL_PROPERTY {}/{} 값을 해석할 수 없어 기본값({})을 사용합니다. : {}", + PROPERTY_GROUP, AGREE_ALL_ENABLED_KEY, DEFAULT_AGREE_ALL_ENABLED, trimmed); + return DEFAULT_AGREE_ALL_ENABLED; + } + + /** + * {@code Portal} 그룹 프로퍼티 전체를 읽는다. + * + *

단건 조회({@code findById})는 중복 행에서 예외가 나므로 그룹 단위로 읽는다. + */ + private Map readGroupProperties() { + return portalPropertyService.getPortalPropertiesAsMap(PROPERTY_GROUP); + } + + /** 프로퍼티 값을 약관 종류 목록으로 변환. 미설정이면 기본값, 알 수 없는 코드는 무시한다. */ + private List readTypes(Map properties, String propertyName) { + String value = properties.get(propertyName); + if (value == null) { + return new ArrayList<>(DEFAULT_TYPES); + } + + List types = new ArrayList<>(); + for (String code : value.split(",")) { + String trimmed = code.trim(); + if (trimmed.isEmpty()) { + continue; + } + try { + types.add(AgreementType.valueOf(trimmed)); + } catch (IllegalArgumentException e) { + log.warn("PTL_PROPERTY {}/{} 에 알 수 없는 약관 종류 코드가 있어 무시합니다. : {}", + PROPERTY_GROUP, propertyName, trimmed); + } + } + return new ArrayList<>(new LinkedHashSet<>(types)); + } +}