This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.eactive.eai.rms.onl.apim.portalnotice;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class IncidentAffectedApiUI {
|
||||
private String apiId;
|
||||
private String apiName;
|
||||
}
|
||||
+136
-1
@@ -1,5 +1,13 @@
|
||||
package com.eactive.eai.rms.onl.apim.portalnotice;
|
||||
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.DjbApistatusIncident;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.DjbApistatusIncidentApi;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.DjbApistatusIncidentApiId;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.IncidentKind;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.entity.IncidentState;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentApiRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentRepository;
|
||||
import com.eactive.apim.portal.djb.apistatus.incident.repository.DjbApistatusIncidentTimelineRepository;
|
||||
import com.eactive.apim.portal.file.entity.FileDetail;
|
||||
import com.eactive.apim.portal.file.entity.FileInfo;
|
||||
import com.eactive.apim.portal.file.service.FileService;
|
||||
@@ -23,7 +31,12 @@ import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
@@ -32,6 +45,9 @@ public class PortalNoticeManService extends BaseService {
|
||||
private final PortalNoticeService portalNoticeService;
|
||||
private final PortalNoticeUIMapper portalNoticeUIMapper;
|
||||
private final FileService fileService;
|
||||
private final DjbApistatusIncidentRepository incidentRepository;
|
||||
private final DjbApistatusIncidentApiRepository incidentApiRepository;
|
||||
private final DjbApistatusIncidentTimelineRepository incidentTimelineRepository;
|
||||
|
||||
private String decodeString(String value) {
|
||||
if (ContainerUtil.get() == ContainerUtil.TOMCAT) {
|
||||
@@ -48,10 +64,27 @@ public class PortalNoticeManService extends BaseService {
|
||||
@Autowired
|
||||
public PortalNoticeManService(PortalNoticeService portalNoticeService,
|
||||
PortalNoticeUIMapper portalNoticeUIMapper,
|
||||
FileService fileService){
|
||||
FileService fileService,
|
||||
DjbApistatusIncidentRepository incidentRepository,
|
||||
DjbApistatusIncidentApiRepository incidentApiRepository,
|
||||
DjbApistatusIncidentTimelineRepository incidentTimelineRepository){
|
||||
this.portalNoticeService = portalNoticeService;
|
||||
this.portalNoticeUIMapper = portalNoticeUIMapper;
|
||||
this.fileService = fileService;
|
||||
this.incidentRepository = incidentRepository;
|
||||
this.incidentApiRepository = incidentApiRepository;
|
||||
this.incidentTimelineRepository = incidentTimelineRepository;
|
||||
}
|
||||
|
||||
private static boolean isIncidentKind(String noticeType) {
|
||||
return PortalNoticeUI.NOTICE_TYPE_INCIDENT.equals(noticeType)
|
||||
|| PortalNoticeUI.NOTICE_TYPE_MAINTENANCE.equals(noticeType);
|
||||
}
|
||||
|
||||
private static IncidentKind toKind(String noticeType) {
|
||||
if (PortalNoticeUI.NOTICE_TYPE_INCIDENT.equals(noticeType)) return IncidentKind.INCIDENT;
|
||||
if (PortalNoticeUI.NOTICE_TYPE_MAINTENANCE.equals(noticeType)) return IncidentKind.MAINTENANCE;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,9 +122,39 @@ public class PortalNoticeManService extends BaseService {
|
||||
|
||||
PortalNoticeUI ui = portalNoticeUIMapper.toVo(portalNotice);
|
||||
setFileInfo(portalNotice, ui);
|
||||
populateIncident(portalNotice, ui);
|
||||
return ui;
|
||||
}
|
||||
|
||||
private void populateIncident(PortalNotice portalNotice, PortalNoticeUI ui) {
|
||||
if (!isIncidentKind(portalNotice.getNoticeType())) {
|
||||
ui.setAffectedApis(Collections.emptyList());
|
||||
return;
|
||||
}
|
||||
Optional<DjbApistatusIncident> incidentOpt = incidentRepository.findByNoticeId(portalNotice.getId());
|
||||
if (!incidentOpt.isPresent()) {
|
||||
ui.setAffectedApis(Collections.emptyList());
|
||||
return;
|
||||
}
|
||||
DjbApistatusIncident incident = incidentOpt.get();
|
||||
ui.setIncidentId(incident.getIncidentId());
|
||||
ui.setSummary(incident.getSummary());
|
||||
ui.setStartedAt(incident.getStartedAt());
|
||||
ui.setEndAt(incident.getEndAt());
|
||||
ui.setState(incident.getState() == null ? null : incident.getState().name());
|
||||
ui.setPreviousState(incident.getPreviousState() == null ? null : incident.getPreviousState().name());
|
||||
|
||||
List<IncidentAffectedApiUI> apis = incidentApiRepository
|
||||
.findByIncidentIdOrderByApiId(incident.getIncidentId()).stream()
|
||||
.map(api -> {
|
||||
IncidentAffectedApiUI vo = new IncidentAffectedApiUI();
|
||||
vo.setApiId(api.getApiId());
|
||||
vo.setApiName(api.getApiName());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
ui.setAffectedApis(apis);
|
||||
}
|
||||
|
||||
public void insert(PortalNoticeUI portalNoticeUI) throws IOException {
|
||||
//portalNoticeUI.setNoticeSubject(decodeString(portalNoticeUI.getNoticeSubject()));
|
||||
//portalNoticeUI.setNoticeDetail(decodeString(StringEscapeUtils.unescapeHtml(portalNoticeUI.getNoticeDetail())));
|
||||
@@ -106,6 +169,61 @@ public class PortalNoticeManService extends BaseService {
|
||||
}
|
||||
|
||||
portalNoticeService.save(portalNotice);
|
||||
|
||||
if (isIncidentKind(portalNoticeUI.getNoticeType())) {
|
||||
persistIncident(portalNoticeUI, portalNotice, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void persistIncident(PortalNoticeUI portalNoticeUI, PortalNotice portalNotice, boolean isCreate) {
|
||||
IncidentKind kind = toKind(portalNoticeUI.getNoticeType());
|
||||
|
||||
DjbApistatusIncident incident = incidentRepository.findByNoticeId(portalNotice.getId())
|
||||
.orElseGet(DjbApistatusIncident::new);
|
||||
|
||||
incident.setKind(kind);
|
||||
incident.setTitle(portalNotice.getNoticeSubject());
|
||||
incident.setSummary(portalNoticeUI.getSummary());
|
||||
incident.setStartedAt(portalNoticeUI.getStartedAt() != null
|
||||
? portalNoticeUI.getStartedAt() : LocalDateTime.now());
|
||||
incident.setEndAt(portalNoticeUI.getEndAt());
|
||||
incident.setDetectedBy("MANUAL");
|
||||
incident.setNoticeId(portalNotice.getId());
|
||||
incident.setDraftYn("N");
|
||||
incident.setFixYn(StringUtils.defaultIfBlank(portalNotice.getFixYn(), "N"));
|
||||
|
||||
if (kind == IncidentKind.INCIDENT) {
|
||||
IncidentState newState = StringUtils.isNotBlank(portalNoticeUI.getState())
|
||||
? IncidentState.valueOf(portalNoticeUI.getState())
|
||||
: IncidentState.INVESTIGATING;
|
||||
if (!isCreate && incident.getState() != newState) {
|
||||
incident.setPreviousState(incident.getState());
|
||||
}
|
||||
incident.setState(newState);
|
||||
} else {
|
||||
incident.setState(null);
|
||||
incident.setPreviousState(null);
|
||||
}
|
||||
|
||||
DjbApistatusIncident saved = incidentRepository.save(incident);
|
||||
|
||||
// 영향 API 동기화 — 단순 전체 삭제 후 재삽입
|
||||
incidentApiRepository.deleteByIncidentId(saved.getIncidentId());
|
||||
List<IncidentAffectedApiUI> affected = portalNoticeUI.getAffectedApis();
|
||||
if (affected != null && !affected.isEmpty()) {
|
||||
List<DjbApistatusIncidentApi> rows = new ArrayList<>();
|
||||
for (IncidentAffectedApiUI src : affected) {
|
||||
if (StringUtils.isBlank(src.getApiId())) continue;
|
||||
DjbApistatusIncidentApi api = new DjbApistatusIncidentApi();
|
||||
api.setIncidentId(saved.getIncidentId());
|
||||
api.setApiId(src.getApiId());
|
||||
api.setApiName(src.getApiName());
|
||||
rows.add(api);
|
||||
}
|
||||
if (!rows.isEmpty()) {
|
||||
incidentApiRepository.saveAll(rows);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFileUpload(PortalNoticeUI portalNoticeUI, PortalNotice portalNotice) throws IOException {
|
||||
@@ -129,6 +247,7 @@ public class PortalNoticeManService extends BaseService {
|
||||
portalNoticeUI.setNoticeDetail(StringEscapeUtils.unescapeHtml(portalNoticeUI.getNoticeDetail()));
|
||||
|
||||
PortalNotice portalNotice = portalNoticeService.getById(portalNoticeUI.getId());
|
||||
String previousNoticeType = portalNotice.getNoticeType();
|
||||
|
||||
if (portalNoticeUI.getFiles() != null && !portalNoticeUI.getFiles().isEmpty()) {
|
||||
handleFileUpload(portalNoticeUI, portalNotice);
|
||||
@@ -139,11 +258,27 @@ public class PortalNoticeManService extends BaseService {
|
||||
|
||||
portalNoticeUIMapper.updateToEntity(portalNoticeUI, portalNotice);
|
||||
portalNoticeService.save(portalNotice);
|
||||
|
||||
if (isIncidentKind(portalNotice.getNoticeType())) {
|
||||
persistIncident(portalNoticeUI, portalNotice, false);
|
||||
} else if (isIncidentKind(previousNoticeType)) {
|
||||
// 일반 공지로 유형 변경 → 기존 incident 정리
|
||||
deleteIncidentIfExists(portalNotice.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteIncidentIfExists(String noticeId) {
|
||||
incidentRepository.findByNoticeId(noticeId).ifPresent(incident -> {
|
||||
incidentApiRepository.deleteByIncidentId(incident.getIncidentId());
|
||||
incidentTimelineRepository.deleteByIncidentId(incident.getIncidentId());
|
||||
incidentRepository.delete(incident);
|
||||
});
|
||||
}
|
||||
|
||||
public void delete(String id) {
|
||||
PortalNotice portalNotice = portalNoticeService.getById(id);
|
||||
Optional.ofNullable(portalNotice.getFileId()).ifPresent(fileService::deleteFile);
|
||||
deleteIncidentIfExists(id);
|
||||
portalNoticeService.deleteById(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,16 @@ import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class PortalNoticeUI {
|
||||
|
||||
public static final String NOTICE_TYPE_NORMAL = "1";
|
||||
public static final String NOTICE_TYPE_MAINTENANCE = "2";
|
||||
public static final String NOTICE_TYPE_INCIDENT = "3";
|
||||
|
||||
private String id;
|
||||
|
||||
private String noticeSubject;
|
||||
@@ -53,4 +58,24 @@ public class PortalNoticeUI {
|
||||
private boolean hasAttachment; // 첨부파일 여부
|
||||
|
||||
private boolean fileDeleted; // 파일 삭제 여부
|
||||
|
||||
// ───── 장애/점검(djb_apistatus_incident) 연동 필드 ─────
|
||||
private Long incidentId;
|
||||
|
||||
private String summary;
|
||||
|
||||
// HTML <input type="datetime-local"> 는 'T' 구분자 형식 (예: 2026-06-16T10:29).
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
|
||||
private LocalDateTime startedAt;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
|
||||
private LocalDateTime endAt;
|
||||
|
||||
private String state; // INCIDENT 한정 (INVESTIGATING/IDENTIFIED/MONITORING/RESOLVED/CANCELED)
|
||||
|
||||
private String previousState; // 직전 상태
|
||||
|
||||
private List<IncidentAffectedApiUI> affectedApis;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ package com.eactive.eai.rms.onl.apim.portalnotice;
|
||||
import com.eactive.apim.portal.portalNotice.entity.PortalNotice;
|
||||
import org.mapstruct.*;
|
||||
|
||||
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
@Mapper(componentModel = "spring",
|
||||
unmappedTargetPolicy = ReportingPolicy.IGNORE,
|
||||
unmappedSourcePolicy = ReportingPolicy.IGNORE)
|
||||
public interface PortalNoticeUIMapper {
|
||||
|
||||
PortalNoticeUI toVo(PortalNotice entity);
|
||||
|
||||
Reference in New Issue
Block a user