package kr.wisestone.owl.service.impl; import com.google.common.collect.Lists; import kr.wisestone.owl.constant.Constants; import kr.wisestone.owl.constant.ElasticSearchConstants; import kr.wisestone.owl.constant.MsgConstants; import kr.wisestone.owl.data.CheckIssueData; import kr.wisestone.owl.domain.*; import kr.wisestone.owl.domain.enumType.CustomFieldType; import kr.wisestone.owl.domain.enumType.IssueHistoryType; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.mapper.IssueHistoryMapper; import kr.wisestone.owl.repository.IssueHistoryRepository; import kr.wisestone.owl.service.*; import kr.wisestone.owl.util.*; import kr.wisestone.owl.vo.IssueHistoryVo; import kr.wisestone.owl.vo.IssueVo; import kr.wisestone.owl.web.condition.IssueHistoryCondition; import kr.wisestone.owl.web.form.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.util.*; @Service public class IssueHistoryServiceImpl extends AbstractServiceImpl> implements IssueHistoryService { private static final Logger log = LoggerFactory.getLogger(IssueHistoryServiceImpl.class); @Autowired private IssueHistoryRepository issueHistoryRepository; @Autowired private UserService userService; @Autowired private DepartmentService departmentService; @Autowired private IssueHistoryMapper issueHistoryMapper; @Autowired private IssueRiskService issueRiskService; @Autowired private IssueCustomFieldValueService issueCustomFieldValueService; @Value("${email.userName}") private String systemEmail; @Override protected JpaRepository getRepository() { return this.issueHistoryRepository; } // 이력 생성 @Override @Transactional public void addIssueHistory(Issue issue, IssueHistoryType issueHistoryType, String issueChangeDescription) { User user = this.webAppUtil.getLoginUserObject(); addIssueHistory(issue, user, issueHistoryType, issueChangeDescription); } // 이력 생성 @Override @Transactional public void addIssueHistory(Issue issue, User user, IssueHistoryType issueHistoryType, String issueChangeDescription) { IssueHistory issueHistory = new IssueHistory(); issueHistory.setIssue(issue); issueHistory.setProject(issue.getProject()); issueHistory.setIssueHistoryType(issueHistoryType); StringBuilder description = new StringBuilder(); // 이력 정보를 만들어 낸다. this.makeDescription(user, description, issueHistoryType, issueChangeDescription); issueHistory.setDescription(description.toString()); this.issueHistoryRepository.saveAndFlush(issueHistory); // 비슷한 시간에 연속적으로 기록을 남겼는지 확인하고 발견된 기록을 묶어서 저장한다. this.detectSameTimeIssueHistory(issue); } // 이력 정보를 만들어 낸다. @Override public void makeDescription(StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) { User user = this.webAppUtil.getLoginUserObject(); makeDescription(user, description, issueHistoryType, issueChangeDescription); } // 이력 정보를 만들어 낸다. @Override public void makeDescription(User user, StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) { description.append("
"); // 생성, 수정, 삭제에 대해 기록을 남긴다. switch (issueHistoryType) { case ADD: description.append("
이슈 생성"); description.append(""); description.append(DateUtil.convertDateToStr(new Date())); description.append(" ("); description.append(user.getName()); description.append(" - "); description.append(CommonUtil.decryptAES128(user.getAccount())); description.append(")"); description.append("
"); break; case MODIFY: description.append("
이슈 변경"); description.append(""); description.append(DateUtil.convertDateToStr(new Date())); description.append(" ("); if (user != null) { description.append(user.getName()); description.append(" - "); description.append(CommonUtil.decryptAES128(user.getAccount())); } else { description.append("OWL-ITS-SYSTEM"); description.append(" - "); description.append(this.systemEmail); } description.append(")"); description.append("
"); description.append(issueChangeDescription); break; case DELETE: description.append("
이슈 삭제"); description.append(""); description.append(DateUtil.convertDateToStr(new Date())); description.append(" ("); description.append(user.getName()); description.append(" - "); description.append(CommonUtil.decryptAES128(user.getAccount())); description.append(")"); description.append("
"); break; case SEND: description.append("
이슈 메일 전송"); description.append(""); description.append(DateUtil.convertDateToStr(new Date())); description.append(" ("); if (user != null) { description.append(user.getName()); description.append(" - "); description.append(CommonUtil.decryptAES128(user.getAccount())); } else { description.append("OWL-ITS-SYSTEM"); description.append(" - "); description.append(this.systemEmail); } description.append(")"); description.append("
"); description.append(issueChangeDescription); break; } description.append("
"); } // 비슷한 시간에 연속적으로 기록을 남겼는지 확인하고 발견된 기록을 묶어서 저장한다. private void detectSameTimeIssueHistory(Issue issue) { StringBuilder description = new StringBuilder(); List issueHistoryVos = this.issueHistoryRepository.findByIssueId(issue.getId()); List saveIssueHistoryVos = Lists.newArrayList(); for (int count = 0; count < (issueHistoryVos.size() - 1); count++) { IssueHistoryVo issueHistoryVo = issueHistoryVos.get(count); IssueHistoryVo nextIssueHistoryVo = issueHistoryVos.get(count + 1); Date beginDate = DateUtil.convertStrToDate(issueHistoryVo.getRegisterDate()); Date endDate = DateUtil.convertStrToDate(nextIssueHistoryVo.getRegisterDate()); long diff = beginDate.getTime() - endDate.getTime(); // 1분 이내에 기록된 이슈 변경 내역은 합친다. if ((diff/1000) < 61) { // 중복된 이슈 이력이 있는지 확인하고 중복되지 않았으면 배열에 추가한다. this.checkDuplicationHistoryList(saveIssueHistoryVos, issueHistoryVo); // 중복된 이슈 이력이 있는지 확인하고 중복되지 않았으면 배열에 추가한다. this.checkDuplicationHistoryList(saveIssueHistoryVos, nextIssueHistoryVo); } } List removeIds = Lists.newArrayList(); for (IssueHistoryVo issueHistoryVo : saveIssueHistoryVos) { description.append(issueHistoryVo.getDescription()); removeIds.add(issueHistoryVo.getId()); } // 합친 기록 생성 if (removeIds.size() > 0) { Long lastUpdateIssueHistoryId = removeIds.get(removeIds.size() - 1); // 마지막 대상에 기록을 옮긴다. IssueHistory issueHistory = this.findOne(lastUpdateIssueHistoryId); issueHistory.setIssueHistoryType(IssueHistoryType.TOTAL); issueHistory.setDescription(description.toString()); this.issueHistoryRepository.saveAndFlush(issueHistory); // 이전 기록 삭제 for (Long removeId : removeIds) { // 마지막 대상은 삭제하지 않는다. if (!lastUpdateIssueHistoryId.equals(removeId)) { this.issueHistoryRepository.deleteById(removeId); } } } } // 중복된 이슈 이력이 있는지 확인하고 중복되지 않았으면 배열에 추가한다. private void checkDuplicationHistoryList(List issueHistoryVos, IssueHistoryVo issueHistoryVo) { boolean duplicate = false; for (IssueHistoryVo historyVo : issueHistoryVos) { if (historyVo.getId().equals(issueHistoryVo.getId())) { duplicate = true; break; } } if (!duplicate) { issueHistoryVos.add(issueHistoryVo); } } // 해당 사용자의 이슈 기록 정보를 가져온다. @Override @Transactional(readOnly = true) public void findIssueHistory(Map resJsonData, IssueHistoryCondition issueHistoryCondition) { // 조회하는 사용자 정보 issueHistoryCondition.setUserId(this.webAppUtil.getLoginId()); if (StringUtils.isEmpty(issueHistoryCondition.getSearchPeriod())) { issueHistoryCondition.setSearchPeriod(DateUtil.LAST_SEVEN_DAYS); } // 검색 조건 직접 입력이 아닐 경우 if (!issueHistoryCondition.getSearchPeriod().equals(DateUtil.CUSTOM_INPUT)) { // 검색 일자를 구한다. List searchDates = CommonUtil.findSearchPeriod(issueHistoryCondition.getSearchPeriod()); // 날짜가 검색되지 않았으면 오류 if (searchDates.size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.WIDGET_SEARCH_DATE_NOT_FOUND)); } // 검색 조건에 시작일, 종료일을 설정한다. issueHistoryCondition.setSearchStartDate(DateUtil.convertDateToYYYYMMDD(searchDates.get(0))); issueHistoryCondition.setSearchEndDate(DateUtil.convertDateToYYYYMMDD(DateUtil.addDays(searchDates.get(searchDates.size() - 1), 1))); } else { issueHistoryCondition.setSearchStartDate(DateUtil.convertDateToStr(DateUtil.convertStrToDate(issueHistoryCondition.getSearchStartDate(), "yyyy-MM-dd"))); issueHistoryCondition.setSearchEndDate(DateUtil.convertDateToStr(DateUtil.addDays(DateUtil.convertStrToDate(issueHistoryCondition.getSearchEndDate(), "yyyy-MM-dd"), 1))); } List> results = this.issueHistoryMapper.find(issueHistoryCondition); Map issueHistoryMaps = new HashMap<>(); Map issueHistoryGroups = new HashMap<>(); issueHistoryMaps.put("searchStartDate", issueHistoryCondition.getSearchStartDate()); issueHistoryMaps.put("searchEndDate", issueHistoryCondition.getSearchEndDate()); for (Map result : results) { IssueHistoryVo issueHistoryVo = ConvertUtil.convertMapToClass(result, IssueHistoryVo.class); List issueHistoryVos = Lists.newArrayList(); String recodeDate = issueHistoryVo.getRegisterDate(); // 해당 요일에 정보가 없을 경우 배열을 만들어 이슈 기록 정보를 담는다. if (MapUtil.getObject(issueHistoryGroups, recodeDate) == null) { issueHistoryVos.add(issueHistoryVo); issueHistoryGroups.put(recodeDate, issueHistoryVos); } else { // 있을 경우에는 해당 배열을 가져와 이슈 기록 정보를 추가한다. issueHistoryVos = (List)MapUtil.getObject(issueHistoryGroups, recodeDate); issueHistoryVos.add(issueHistoryVo); } if (issueHistoryVos.size() > 0) { issueHistoryGroups.put(recodeDate, issueHistoryVos); } } issueHistoryMaps.put("issueHistoryGroups", issueHistoryGroups); resJsonData.put(Constants.RES_KEY_CONTENTS, issueHistoryMaps); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_HISTORY_FIND)); } // 이슈 아이디에 해당하는 기록 정보를 가져온다. @Override @Transactional(readOnly = true) public List findIssueHistory(Issue issue) { List issueHistoryVos = this.issueHistoryRepository.findByIssueId(issue.getId()); if (issueHistoryVos != null && issueHistoryVos.size() > 0) { for (IssueHistoryVo issueHistoryVo : issueHistoryVos) { issueHistoryVo.setTitle(issue.getTitle()); } } return issueHistoryVos; } // 이슈 변경 내역을 추출한다. @Override public StringBuilder detectIssueChange(IssueForm issueForm, CheckIssueData data, List files) { return this.detectIssueChange(data.getIssue(), issueForm, data.getProject(), data.getOldIssueStatus(), data.getNewIssueStatus(), data.getIssueType(), data.getPriority(), data.getSeverity(), files); } // 이슈 변경 내역을 추출한다. @Override public StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus oldIssueStatus, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List files) { StringBuilder description = new StringBuilder(); // 이슈 프로젝트 변경 정보를 기록한다. this.detectProject(issue, issueForm, description, project); // 이슈 중요도 변경 정보를 기록한다. this.detectIssueSeverity(issue, issueForm, description, severity); // 이슈 우선순위 변경 정보를 기록한다. this.detectIssuePriority(issue, issueForm, description, priority); // 이슈 상태 변경 정보를 기록한다. this.detectIssueStatus(issue, issueForm, description, oldIssueStatus, issueStatus); // 이슈 타입 변경 정보를 기록한다. this.detectIssueType(issue, issueForm, description, issueType); // 이슈에 첨부된 파일에 대해 변경 정보를 기록한다. this.detectAttachedFile(issueForm, description, files); // 이슈 기간 변경 정보를 기록한다. this.detectIssuePeriod(issue, issueForm, description); // 담당자 변경 정보를 기록한다. this.detectIssueManager(issue, issueForm, description); if (issueForm.getIsApi().equals(Issue.IS_API_NO)) { //api로 변경 시 담당부서 변경 불가 // 담당부서 변경 정보를 기록한다. this.detectIssueDepartment(issue, issueForm, description); } // 사용자 정의 필드 변경 정보를 기록한다. this.detectCustomField(issue, issueForm, description); // 이슈 제목 변경 정보를 기록한다. if (!issue.getTitle().equals(issueForm.getTitle())) { description.append("
  • 제목이 변경되었습니다.
  • "); } // 이슈 내용 변경 정보를 기록한다. if (!issue.getDescription().equals(issueForm.getDescription())) { description.append("
  • 내용이 변경되었습니다.
  • "); } if (description.toString().length() > 1){ StringBuilder firstEnd = new StringBuilder(); firstEnd.append("
      "); firstEnd.append(description.toString()); firstEnd.append("
    "); return firstEnd; } return description; } // 이슈 프로젝트 변경 정보를 기록한다. @Override public void detectProject(Issue issue, IssueForm issueForm, StringBuilder description, Project project) { if (!issue.getProject().getId().equals(issueForm.getProjectId())) { String title = "프로젝트가 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, issue.getProject().getName(), project.getName()); } } // 이력 정보를 html 태그로 만들어 준다. private void makeIssueHistoryHtml(StringBuilder description, String title, String beforeValue, String afterValue) { description.append("
  • "); description.append(title); description.append(" "); description.append(beforeValue); description.append(""); description.append(""); description.append(""); description.append(afterValue); description.append(""); description.append("
  • "); } // 이슈 중요도 변경 정보를 기록한다. @Override public void detectIssueSeverity(Issue issue, IssueForm issueForm, StringBuilder description, Severity severity) { if (!issue.getSeverity().getId().equals(issueForm.getSeverityId())) { String title = "중요도가 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, issue.getSeverity().getName(), severity.getName()); } } // 이슈 우선순위 변경 정보를 기록한다. @Override public void detectIssuePriority(Issue issue, IssueForm issueForm, StringBuilder description, Priority priority) { if (!issue.getPriority().getId().equals(issueForm.getPriorityId())) { String title = "우선순위가 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, issue.getPriority().getName(), priority.getName()); } } // 이슈 상태 변경 정보를 기록한다. @Override @Transactional public void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus oldIssueStatus, IssueStatus issueStatus) { if (!oldIssueStatus.getId().equals(issueForm.getIssueStatusId())) { String title = "상태가 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, oldIssueStatus.getName(), issueStatus.getName()); // 이슈 위험 관리에 상태 변경 정보를 업데이트한다. - 담당자 변경 this.issueRiskService.modifyIssueRisk(issue, true, false, issueForm.getIssueStatusId()); } } // 예약 발생으로 이슈 상태 변경된 정보를 기록한다. @Override public void detectReservationIssueStatus(Issue issue, StringBuilder description, IssueStatus issueStatus) { description.append("
      "); String title = "이슈 발생 예약일이 되어 상태가 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, issue.getIssueStatus().getName(), issueStatus.getName()); description.append("
    "); } // 워크플로우에서 이슈 상태가 삭제되어 상태가 변경된 정보를 기록한다. @Override public void recordRemoveWorkflowToIssueStatus(String oldIssueStatusName, String newIssueStatusName, StringBuilder description) { description.append("
      "); String title = "변경된 워크플로우에서 상태가 존재하지 않아 이슈의 상태가 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, oldIssueStatusName, newIssueStatusName); description.append("
    "); } // 이슈 타입 변경 정보를 기록한다. @Override public void detectIssueType(Issue issue, IssueForm issueForm, StringBuilder description, IssueType issueType) { if (!issue.getIssueType().getId().equals(issueForm.getIssueTypeId())) { String title = "이슈 타입이 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, issue.getIssueType().getName(), issueType.getName()); } } // 이슈 기간 변경 정보를 기록한다. @Override public void detectIssuePeriod(Issue issue, IssueForm issueForm, StringBuilder description) { // 기간 신규 설정 또는 기간 삭제시 if ((issue.getStartDate() == null && issueForm.getStartDate() != null) || (issue.getStartDate() != null && issueForm.getStartDate() == null)) { // 기간 변경 정보를 기록한다. this.recodeChangeIssuePeriod(issue, issueForm, description); } if (issue.getStartDate() != null && issueForm.getStartDate() != null) { if (!issue.getStartDate().equals(issueForm.getStartDate()) || !issue.getCompleteDate().equals(issueForm.getCompleteDate())) { // 기간 변경 정보를 기록한다. this.recodeChangeIssuePeriod(issue, issueForm, description); } } } // 기간 변경 정보를 기록한다. private void recodeChangeIssuePeriod(Issue issue, IssueForm issueForm, StringBuilder description) { String title = "기간이 변경되었습니다."; // 기간 정보를 기록한다. String beforePeriod = this.recodeIssuePeriod(issue.getStartDate(), issue.getCompleteDate()); String afterPeriod = this.recodeIssuePeriod(issueForm.getStartDate(), issueForm.getCompleteDate()); // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, beforePeriod, afterPeriod); } // 기간 정보를 기록한다. private String recodeIssuePeriod(String startDate, String completeDate) { StringBuilder recodeIssuePeriod = new StringBuilder(); if (startDate != null) { recodeIssuePeriod.append(startDate); recodeIssuePeriod.append(" ~ "); recodeIssuePeriod.append(completeDate); } else { recodeIssuePeriod.append("미지정"); } return recodeIssuePeriod.toString(); } // 연관 일감 변경 정보를 기록한다. @Override public void detectRelationIssue(IssueHistoryType type, IssueRelation issueRelation, StringBuilder description) { if (type == IssueHistoryType.ADD) { description.append("연관 일감이 추가되었습니다. "); description.append(" > " + issueRelation.getRelationIssue().getTitle() + ""); } else { description.append("연관 일감이 삭제되었습니다. " + issueRelation.getRelationIssue().getTitle() + ""); description.append(" > " + issueRelation.getRelationIssue().getTitle() + ""); } } // 하위 일감 변경 정보를 기록한다. @Override public void detectDownIssues(IssueHistoryType type, Issue issue, StringBuilder description) { if (type == IssueHistoryType.ADD) { description.append("하위 일감이 추가되었습니다. "); description.append(" > " + issue.getTitle() + ""); }else { description.append("하위 일감이 삭제되었습니다. "); description.append(" > " + issue.getTitle() + ""); } } // 이슈 메일 전송 정보를 기록한다. @Override public void detectSendIssueMail(IssueHistoryType type, IssueForm issueForm, StringBuilder description) { this.detectSendIssueMail(type, issueForm.getSendEmails(), description); } // 이슈 메일 전송 정보를 기록한다. @Override public void detectSendIssueMail(IssueHistoryType type, List sendMails, StringBuilder description) { if (type == IssueHistoryType.SEND) { description.append("이슈 메일 전송을 완료했습니다. "); if(sendMails != null && sendMails.size() > 0){ for (String sendEmail : sendMails){ description.append(" > " + CommonUtil.decryptAES128(sendEmail) + ""); } } } } // 업체 정보 변경 정보를 기록한다. @Override @Transactional public void detectIssueCompany(IssueHistoryType type, Map param, CompanyFieldForm companyFieldForm, IssueCompany issueCompany, StringBuilder description) { Long companyFieldId = 0L; Long id = 0L; String name = ""; String manager = ""; String tel = ""; String email = ""; String memo = ""; Long companyTypeId = 0L; Long parentSectorId = 0L; Long childSectorId = 0L; Long regionId = 0L; Long statusId = 0L; String companyTypeName = ""; String parentSectorName = ""; String childSectorName = ""; String regionName = ""; String statusName = ""; if (param != null) { id = MapUtil.getLong(param, "companyId"); name = MapUtil.getString(param, "name"); manager = MapUtil.getString(param, "manager"); tel = MapUtil.getString(param, "tel"); email = MapUtil.getString(param, "email"); memo = MapUtil.getString(param, "memo"); companyTypeId = MapUtil.getLong(param, "companyTypeId"); parentSectorId = MapUtil.getLong(param, "parentSectorId"); childSectorId = MapUtil.getLong(param, "childSectorId"); regionId = MapUtil.getLong(param, "regionId"); statusId = MapUtil.getLong(param, "statusId"); companyTypeName = MapUtil.getString(param, "companyTypeName"); parentSectorName = MapUtil.getString(param, "parentSectorName"); childSectorName = MapUtil.getString(param, "childSectorName"); regionName = MapUtil.getString(param, "regionName"); statusName = MapUtil.getString(param, "statusName"); }else if(companyFieldForm != null) { id = companyFieldForm.getId(); name = companyFieldForm.getName(); manager = companyFieldForm.getManager(); tel = companyFieldForm.getTel(); email = companyFieldForm.getEmail(); memo = companyFieldForm.getMemo(); companyTypeId = companyFieldForm.getCompanyTypeId(); parentSectorId = companyFieldForm.getParentSectorId(); childSectorId = companyFieldForm.getChildSectorId(); regionId = companyFieldForm.getRegionId(); statusId = companyFieldForm.getStatusId(); companyTypeName = companyFieldForm.getCompanyTypeName(); parentSectorName = companyFieldForm.getParentSectorName(); childSectorName = companyFieldForm.getChildSectorName(); regionName = companyFieldForm.getRegionName(); statusName = companyFieldForm.getStatusName(); } if (issueCompany.getCompanyField() != null && issueCompany.getCompanyField().getId() != null) { companyFieldId = issueCompany.getCompanyField().getId(); } if (type == IssueHistoryType.ADD && issueCompany.getCompanyField() != null) { //추가 할 경우 description.append("업체 정보가 추가되었습니다. "); description.append(" > " + issueCompany.getCompanyField().getName() + ""); } else if (type == IssueHistoryType.MODIFY) { //수정 할 경우 if (id != null && !companyFieldId.equals(id)) { description.append("업체 정보가 변경되었습니다. "); description.append(" > " + name + ""); } else { if (companyFieldId.equals(id) && manager != null && (issueCompany.getManager() == null || !issueCompany.getManager().equals(manager))) { description.append(" > 업체 정보의 담당자가 변경되었습니다. "); description.append(" > " + manager + ""); } if (companyFieldId.equals(id) && tel != null && (issueCompany.getTel() == null || !issueCompany.getTel().equals(tel))) { description.append(" > 업체 정보의 전화번호가 변경되었습니다. "); description.append(" > " + tel + ""); } if (companyFieldId.equals(id) && email != null && (issueCompany.getEmail() == null || !issueCompany.getEmail().equals(email))) { description.append(" > 업체 정보의 이메일이 변경되었습니다. "); description.append(" > " + email + ""); } if (companyFieldId.equals(id) && memo != null && (issueCompany.getMemo() == null || !issueCompany.getMemo().equals(memo))) { description.append(" > 업체 정보의 비고가 변경되었습니다. "); description.append(" > " + memo + ""); } if (companyFieldId.equals(id) && companyTypeName != null && (issueCompany.getCompanyTypeId() == null || !issueCompany.getCompanyTypeId().equals(companyTypeId))) { description.append(" > 업체 정보의 기업구분이 변경되었습니다. "); description.append(" > " + companyTypeName + ""); } if (companyFieldId.equals(id) && parentSectorName != null && (issueCompany.getParentSectorId() == null || !issueCompany.getParentSectorId().equals(parentSectorId))) { description.append(" > 업체 정보의 업종(대분류)이 변경되었습니다. "); description.append(" > " + parentSectorName + ""); } if (companyFieldId.equals(id) && childSectorName != null && (issueCompany.getChildSectorId() == null || !issueCompany.getChildSectorId().equals(childSectorId))) { description.append(" > 업체 정보의 업종(중분류)이 변경되었습니다. "); description.append(" > " + childSectorName + ""); } if (companyFieldId.equals(id) && statusName != null && (issueCompany.getStatusId() == null || !issueCompany.getStatusId().equals(statusId))) { description.append(" > 업체 정보의 상태가 변경되었습니다. "); description.append(" > " + statusName + ""); } if (companyFieldId.equals(id) && regionName != null && (issueCompany.getRegionId() == null || !issueCompany.getRegionId().equals(regionId))) { description.append(" > 업체 정보의 지역이 변경되었습니다. "); description.append(" > " + regionName + ""); } } } else { description.append("업체 정보가 삭제되었습니다. " + issueCompany.getCompanyField().getName() + ""); description.append(" > " + issueCompany.getCompanyField().getName() + ""); } } // ISP 정보 변경 정보를 기록한다. @Override public void detectIssueIsp(IssueHistoryType type, Map param, IspFieldForm ispFieldForm, IssueIsp issueIsp, StringBuilder description) { Long ispFieldId = 0L; Long id = 0L; String name = ""; String manager = ""; String tel = ""; String email = ""; String memo = ""; if (param != null) { id = MapUtil.getLong(param, "ispId"); name = MapUtil.getString(param, "name"); manager = MapUtil.getString(param, "manager"); tel = MapUtil.getString(param, "tel"); email = MapUtil.getString(param, "email"); memo = MapUtil.getString(param, "memo"); }else if(ispFieldForm != null) { id = ispFieldForm.getId(); name = ispFieldForm.getName(); manager = ispFieldForm.getManager(); tel = ispFieldForm.getTel(); email = ispFieldForm.getEmail(); memo = ispFieldForm.getMemo(); } if (issueIsp.getIspField() != null && issueIsp.getIspField().getId() != null) { ispFieldId = issueIsp.getIspField().getId(); } if (type == IssueHistoryType.ADD) { description.append("ISP 정보가 추가되었습니다. "); description.append(" > " + issueIsp.getIspField().getName() + ""); } else if (type == IssueHistoryType.MODIFY) { if (id != null && !ispFieldId.equals(id)) { //수정 할 경우 description.append("ISP 정보가 변경되었습니다. "); description.append(" > " + name + ""); } else { if (ispFieldId.equals(id) && manager != null && (issueIsp.getManager() == null || !issueIsp.getManager().equals(manager))) { description.append("ISP 정보의 담당자가 변경되었습니다. "); description.append(" > " + manager + ""); } if (ispFieldId.equals(id) && tel != null && (issueIsp.getTel() == null || !issueIsp.getTel().equals(tel))) { description.append("ISP 정보의 전화번호가 변경되었습니다. "); description.append(" > " + tel + ""); } if (ispFieldId.equals(id) && email != null && (issueIsp.getEmail() == null || !issueIsp.getEmail().equals(email))) { description.append("ISP 정보의 이메일이 변경되었습니다. "); description.append(" > " + email + ""); } if (ispFieldId.equals(id) && memo != null && (issueIsp.getMemo() == null || !issueIsp.getMemo().equals(memo))) { description.append("ISP 정보의 비고가 변경되었습니다. "); description.append(" > " + memo + ""); } } } else { description.append("ISP 정보가 삭제되었습니다. " + issueIsp.getIspField().getName() + ""); description.append(" > " + issueIsp.getIspField().getName() + ""); } } // 호스팅 정보 변경 정보를 기록한다. @Override public void detectIssueHosting(IssueHistoryType type, Map param, HostingFieldForm hostingFieldForm, IssueHosting issueHosting, StringBuilder description) { Long hostingFieldId = 0L; Long id = 0L; String name = ""; String manager = ""; String tel = ""; String email = ""; String memo = ""; if (param != null) { id = MapUtil.getLong(param, "hostingId"); name = MapUtil.getString(param, "name"); manager = MapUtil.getString(param, "manager"); tel = MapUtil.getString(param, "tel"); email = MapUtil.getString(param, "email"); memo = MapUtil.getString(param, "memo"); }else if(hostingFieldForm != null) { id = hostingFieldForm.getId(); name = hostingFieldForm.getName(); manager = hostingFieldForm.getManager(); tel = hostingFieldForm.getTel(); email = hostingFieldForm.getEmail(); memo = hostingFieldForm.getMemo(); } if (issueHosting.getHostingField() != null && issueHosting.getHostingField().getId() != null) { hostingFieldId = issueHosting.getHostingField().getId(); } if (type == IssueHistoryType.ADD) { description.append("호스팅 정보가 추가되었습니다. "); description.append(" > " + issueHosting.getHostingField().getName() + ""); }else if(type == IssueHistoryType.MODIFY){ if(id != null && !hostingFieldId.equals(id)){ //수정 할 경우 description.append("호스팅 정보가 변경되었습니다. "); description.append(" > " + name + ""); } else { if(hostingFieldId.equals(id) && manager != null && (issueHosting.getManager() == null || !issueHosting.getManager().equals(manager))){ description.append("호스팅 정보의 담당자가 변경되었습니다. "); description.append(" > " + manager + ""); } if(hostingFieldId.equals(id) && tel != null && (issueHosting.getTel() == null || !issueHosting.getTel().equals(tel))){ description.append("호스팅 정보의 전화번호가 변경되었습니다. "); description.append(" > " + tel + ""); } if(hostingFieldId.equals(id) && email != null && (issueHosting.getEmail() == null || !issueHosting.getEmail().equals(email))){ description.append("호스팅 정보의 이메일이 변경되었습니다. "); description.append(" > " + email + ""); } if(hostingFieldId.equals(id) && memo != null && (issueHosting.getMemo() == null || !issueHosting.getMemo().equals(memo))){ description.append("호스팅 정보의 비고가 변경되었습니다. "); description.append(" > " + memo + ""); } } } else { description.append("호스팅 정보가 삭제되었습니다. " + issueHosting.getHostingField().getName() + ""); description.append(" > " + issueHosting.getHostingField().getName() + ""); } } // 담당자 변경 정보를 기록한다. @Override public void detectIssueManager(Issue issue, IssueForm issueForm, StringBuilder description) { boolean saveIssueRisk = false; // 이슈 위험 관리에 이중 저장되는 것을 방지하기 위한 구분 값 // 담당자 수가 달려젔을 경우 if (issue.getIssueUsers().size() != issueForm.getUserIds().size()) { this.recodeIssueManager(issue, issueForm, description); // 이슈 위험 관리에 담당자 변경 정보를 업데이트한다. - 담당자 변경 this.issueRiskService.modifyIssueRisk(issue, false, true, null); saveIssueRisk = true; } // 담당자 수는 같으나 사용자가 달라졌을 경우 if (issue.getIssueUsers().size() > 0 && issueForm.getUserIds().size() > 0) { // 이전 담당자 표시 for (IssueUser issueUser : issue.getIssueUsers()) { boolean change = true; User user = issueUser.getUser(); for (Long userId : issueForm.getUserIds()) { if (user.getId().equals(userId)) { change = false; break; } } if (change) { // 담당자 변경 정보 기록 this.recodeIssueManager(issue, issueForm, description); // 담당자수가 달라졌을 경우에 저장되지 않았다면 여기서 이슈 위험 관리 저장을 한다. if (!saveIssueRisk) { // 이슈 위험 관리에 담당자 변경 정보를 업데이트한다. - 담당자 변경 this.issueRiskService.modifyIssueRisk(issue, false, true, null); } break; } } } } // 담당자 변경 정보 기록 private void recodeIssueManager(Issue issue, IssueForm issueForm, StringBuilder description) { String title = "담당자가 변경되었습니다."; StringBuilder beforeUser = new StringBuilder(); // 이전 담당자 표시 for (IssueUser issueUser : issue.getIssueUsers()) { beforeUser.append(issueUser.getUser().getName()); beforeUser.append(", "); } // 담당자가 없었으면 없음으로 표시 if (issue.getIssueUsers().size() < 1) { beforeUser.append("없음"); } StringBuilder afterUser = new StringBuilder(); for (Long userId : issueForm.getUserIds()) { User user = this.userService.getUser(userId); afterUser.append(user.getName()); afterUser.append(", "); } // 담당자가 없었으면 없음으로 표시 if (issueForm.getUserIds().size() < 1) { afterUser.append("없음"); } // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, beforeUser.toString(), afterUser.toString()); } // 담당부서 변경 정보를 기록한다. @Override public void detectIssueDepartment(Issue issue, IssueForm issueForm, StringBuilder description) { boolean saveIssueRisk = false; // 이슈 위험 관리에 이중 저장되는 것을 방지하기 위한 구분 값 // 담당부서 수가 달라졌을 경우 if(issue.getIssueDepartments().size() != issueForm.getDepartmentIds().size()){ this.recodeIssueDepartment(issue, issueForm, description); // 이슈 위험 관리에 담당부서 변경 정보를 업데이트 한다. - 담당부서 변경 this.issueRiskService.modifyIssueRisk(issue, false, true, null); saveIssueRisk = true; }else if (issue.getIssueDepartments().size() > 0 && issueForm.getDepartmentIds().size() > 0) {// 담당부서 수는 같으나 담당부서가 달라졌을 경우 // 이전 담당자 표시 for (IssueDepartment issueDepartment : issue.getIssueDepartments()) { boolean change = true; Department department = issueDepartment.getDepartment(); for (Long departmentId : issueForm.getDepartmentIds()) { if (department.getId().equals(departmentId)) { change = false; break; } } if (change) { // 담당부서 변경 정보 기록 this.recodeIssueDepartment(issue, issueForm, description); // 담당부서 수가 달라졌을 경우에 저장되지 않았다면 여기서 이슈 위험 관리 저장을 한다. if (!saveIssueRisk) { // 이슈 위험 관리에 담당부서 변경 정보를 업데이트한다. - 담당부서 변경 this.issueRiskService.modifyIssueRisk(issue, false, true, null); } break; } } } } // 담당부서 변경 정보 기록 private void recodeIssueDepartment(Issue issue, IssueForm issueForm, StringBuilder description) { String title = "담당부서가 변경되었습니다."; StringBuilder beforeDepartment = new StringBuilder(); // 이전 담당부서 표시 for (IssueDepartment issueDepartment : issue.getIssueDepartments()) { beforeDepartment.append(issueDepartment.getDepartment().getDepartmentName()); beforeDepartment.append(", "); } // 담당부서가 없었으면 없음으로 표시 if (issue.getIssueDepartments().size() < 1) { beforeDepartment.append("없음"); } StringBuilder afterDepartment = new StringBuilder(); for (Long departmentId : issueForm.getDepartmentIds()) { Department department = this.departmentService.getDepartment(departmentId); afterDepartment.append(department.getDepartmentName()); afterDepartment.append(", "); } // 담당부서가 없었으면 없음으로 표시 if (issueForm.getDepartmentIds().size() < 1) { afterDepartment.append("없음"); } // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, beforeDepartment.toString(), afterDepartment.toString()); } // 이슈에 첨부된 파일에 대해 변경 정보를 기록한다. @Override public void detectAttachedFile(IssueForm issueForm, StringBuilder description, List files) { // 삭제 대상이 있거나 새로 업로드 된 파일이 존재할 경우 변경 정보 기록 if (issueForm.getRemoveFiles().size() > 0 && files.size() > 0) { description.append("
  • 첨부 파일이 변경되었습니다.
  • "); } // 삭제 대상이 있거나 새로 업로드 된 파일이 존재할 경우 변경 정보 기록 if (issueForm.getRemoveFiles().size() > 0 && files.size() < 1) { description.append("
  • 첨부 파일이 삭제되었습니다.
  • "); } // 삭제 대상이 있거나 새로 업로드 된 파일이 존재할 경우 변경 정보 기록 if (issueForm.getRemoveFiles().size() < 1 && files.size() > 0) { description.append("
  • 첨부 파일이 등록되었습니다.
  • "); } } // 이슈에서 사용되는 사용자 정의 필드 변경 정보를 기록한다. @Override public void detectCustomField(Issue issue, IssueForm issueForm, StringBuilder description) { // 이슈 폼에서 올라온 사용자 정의 필드 변경 정보를 추출해서 객체로 만든다. List formIssueCustomFieldValues = this.getIssueCustomFieldValuesByIssueForm(issue, issueForm); List passMultiSelectCustomFields = Lists.newArrayList(); for (IssueCustomFieldValue issueCustomFieldValue : formIssueCustomFieldValues) { CustomField customField = issueCustomFieldValue.getCustomField(); switch (customField.getCustomFieldType()) { case INPUT : case SINGLE_SELECT : case NUMBER : case DATETIME : case IP_ADDRESS : case EMAIL : case SITE : case TEL : boolean existIssueCustomFieldValue = false; for (IssueCustomFieldValue savedIssueCustomFieldValue : issue.getIssueCustomFieldValues()) { if (customField.getId().equals(savedIssueCustomFieldValue.getCustomField().getId())) { existIssueCustomFieldValue = true; if (!issueCustomFieldValue.getUseValue().equals(savedIssueCustomFieldValue.getUseValue())) { // 기존에 있던 값을 변경한 경우 this.recodeCustomFieldValue(savedIssueCustomFieldValue.getUseValue(), issueCustomFieldValue.getUseValue(), customField.getName(), description, customField.getCustomFieldType()); } break; } } if (!existIssueCustomFieldValue) { // 기존에 저장된 내역이 없으면서 신규로 저장한 값이 공백일 경우는 저장하지 않는다. if (!StringUtils.isEmpty(issueCustomFieldValue.getUseValue())) { // 신규로 값을 저장한 경우 this.recodeCustomFieldValue("", issueCustomFieldValue.getUseValue(), customField.getName(), description, customField.getCustomFieldType()); } } break; case MULTI_SELECT : this.recodeCaseMultiSelect(customField, issue, formIssueCustomFieldValues, passMultiSelectCustomFields, description); break; } } } // 이슈 폼에서 올라온 사용자 정의 필드 변경 정보를 추출해서 객체로 만든다. private List getIssueCustomFieldValuesByIssueForm(Issue issue, IssueForm issueForm) { List formIssueCustomFieldValues = Lists.newArrayList(); // 변경하려는 사용자 정의 필드 값을 IssueCustomFieldValue 객체로 만든다. for (Map map : issueForm.getIssueCustomFields()) { Map result = new HashMap<>(); // customFieldVo 에서 사용자 정의 필드와 이슈 유형에 연결된 사용자 정의 필드 정보를 가져온다. this.issueCustomFieldValueService.getCustomFieldAndIssueTypeCustomField(map, issue, result); CustomField customField = (CustomField)result.get("customField"); IssueTypeCustomField issueTypeCustomField = (IssueTypeCustomField)result.get("issueTypeCustomField"); List useValues = MapUtil.getStrings(map, "useValues"); if (useValues != null) { for (String useValue : useValues) { IssueCustomFieldValue issueCustomFieldValue = new IssueCustomFieldValue(issue, customField, issueTypeCustomField, useValue); formIssueCustomFieldValues.add(issueCustomFieldValue); } // 이슈 수정에서 사용자 정의 필드를 선택하지 않았을 경우에는 useValue 값을 공백으로 해서 객체를 생성한다. if (useValues.size() < 1) { IssueCustomFieldValue issueCustomFieldValue = new IssueCustomFieldValue(issue, customField, issueTypeCustomField, ""); formIssueCustomFieldValues.add(issueCustomFieldValue); } } } return formIssueCustomFieldValues; } // 멀티 셀렉트 유형에 대해 변경 내역을 확인하고 기록한다. private void recodeCaseMultiSelect(CustomField customField, Issue issue, List formIssueCustomFieldValues, List passMultiSelectCustomFields, StringBuilder description) { boolean passMultiSelect = false; // 한번 체크한 멀티 셀렉트는 더 이상 변경 내역을 저장하지 않는다. (issue custom field value 에는 멀티셀렉트 값 마다 저장되어있어서...) for (Long passMultiSelectCustomFieldId : passMultiSelectCustomFields) { if (customField.getId().equals(passMultiSelectCustomFieldId)) { passMultiSelect = true; break; } } if (passMultiSelect) { return; } else { passMultiSelectCustomFields.add(customField.getId()); } // 폼에 있는 멀티 셀렉트 값 추출 - 해당 사용자 정의 필드에서 사용된 값 List formCustomFieldValues = this.getMultiSelectCustomFieldValues(customField, formIssueCustomFieldValues); // 저장되어 있는 멀티 셀렉트 값을 추출 List savedCustomFieldValues = this.getMultiSelectCustomFieldValues(customField, Lists.newArrayList(issue.getIssueCustomFieldValues())); // 변경 정보 저장 if (formCustomFieldValues.size() != savedCustomFieldValues.size()) { this.recodeMultiSelectCustomFieldValue(savedCustomFieldValues, formCustomFieldValues, customField.getName(), description); } else { for (String formCustomFieldValue : formCustomFieldValues) { boolean checkValue = false; for (String savedCustomFieldValue : savedCustomFieldValues) { if (formCustomFieldValue.equals(savedCustomFieldValue)) { checkValue = true; break; } } if (!checkValue) { // 변경 정보 저장 this.recodeMultiSelectCustomFieldValue(savedCustomFieldValues, formCustomFieldValues, customField.getName(), description); break; } } } } // 멀티 셀렉트에 있는 사용자 정의 필드 값을 추출한다. private List getMultiSelectCustomFieldValues(CustomField customField, List issueCustomFieldValues) { List customFieldValues = Lists.newArrayList(); // 폼에 있는 멀티 셀렉트 값 추출 for (IssueCustomFieldValue issueCustomFieldValue : issueCustomFieldValues) { if (issueCustomFieldValue.getCustomField().getCustomFieldType().equals(CustomFieldType.MULTI_SELECT) && customField.getId().equals(issueCustomFieldValue.getCustomField().getId())) { if (!StringUtils.isEmpty(issueCustomFieldValue.getUseValue())) { customFieldValues.add(issueCustomFieldValue.getUseValue()); } } } return customFieldValues; } // 멀티 셀렉트의 변경된 값을 기록한다. private void recodeMultiSelectCustomFieldValue(List oldValues, List newValues, String customFieldName, StringBuilder description) { StringBuilder oldValueBuilder = new StringBuilder(); StringBuilder newValueBuilder = new StringBuilder(); // 배열에서 값을 추출한다. this.setListValue(oldValues, oldValueBuilder); // 배열에서 값을 추출한다. this.setListValue(newValues, newValueBuilder); // 사용자 정의 필드 변경 정보를 저장한다. this.recodeCustomFieldValue(oldValueBuilder.toString(), newValueBuilder.toString(), customFieldName, description, CustomFieldType.MULTI_SELECT); } // 배열에서 값을 추출한다. private void setListValue(List values, StringBuilder stringBuilder) { for (String value : values) { stringBuilder.append(value); stringBuilder.append(", "); } } // 사용자 정의 필드 변경 정보를 저장한다. private void recodeCustomFieldValue(String oldValue, String newValue, String customFieldName, StringBuilder description, CustomFieldType customFieldType) { String title = "(" + customFieldName + ")사용자 정의 필드가 변경되었습니다."; // 기록에 남기는 사용자 정의 필드가 공백 값이면 알아볼 수 있게 알림을 넣어준다. String beforeValue = this.checkEmptyCustomFieldValue(oldValue, customFieldType); String afterValue = this.checkEmptyCustomFieldValue(newValue, customFieldType); // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, beforeValue, afterValue); } // 기록에 남기는 사용자 정의 필드가 공백 값이면 알아볼 수 있게 알림을 넣어준다. private String checkEmptyCustomFieldValue(String value, CustomFieldType customFieldType) { String result = ""; if (StringUtils.isEmpty(value)) { switch(customFieldType) { case INPUT: case NUMBER: case DATETIME: case IP_ADDRESS: case EMAIL: case SITE: case TEL: result = "입력한 값이 없습니다."; break; case SINGLE_SELECT: case MULTI_SELECT: result = "선택한 값이 없습니다."; break; } } else { result = value; } return result; } // 사용자 정의 필드의 옵션 값이 삭제되어 이슈에서 사용된 값이 삭제될 경우 변경 정보를 저장한다. @Override @Transactional public void recodeRemoveCustomFieldOptionValue(CustomField customField, String oldValue, String newValue, StringBuilder description) { description.append("
      "); String title = "(" + customField.getName() + ")사용자 정의 필드 옵션 값이 변경되어 이슈의 사용자 정의 필드 값이 변경되었습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, oldValue, newValue); description.append("
    "); } // 사용자 정의 필드 유형이 변경되어 이슈에서 사용된 옵션 값이 삭제되었다고 저장한다. @Override @Transactional public void recodeChangeCustomFieldType(CustomField customField, String oldValue, StringBuilder description) { description.append("
      "); String title = "(" + customField.getName() + ")사용자 정의 필드 유형이 변경되어 이슈의 사용자 정의 필드 값이 변경되었습니다."; String newValue = "입력한 값이 없습니다."; // 이력 정보를 html 태그로 만들어 준다. this.makeIssueHistoryHtml(description, title, oldValue, newValue); description.append("
    "); } }