package kr.wisestone.owl.service.impl; import com.google.common.collect.Lists; import kr.wisestone.owl.common.ExcelConditionCheck; import kr.wisestone.owl.common.IssueCustomFieldValueFormComparator; import kr.wisestone.owl.config.CommonConfiguration; import kr.wisestone.owl.constant.*; import kr.wisestone.owl.data.CheckIssueData; import kr.wisestone.owl.domain.*; import kr.wisestone.owl.domain.enumType.CustomFieldType; import kr.wisestone.owl.domain.enumType.EmailType; import kr.wisestone.owl.domain.enumType.IssueHistoryType; import kr.wisestone.owl.domain.enumType.IssueStatusType; import kr.wisestone.owl.exception.ApiAuthException; import kr.wisestone.owl.exception.ApiParameterException; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.mapper.DepartmentMapper; import kr.wisestone.owl.mapper.IssueMapper; import kr.wisestone.owl.mapper.IssueRelationMapper; import kr.wisestone.owl.mapper.ProjectMapper; import kr.wisestone.owl.repository.*; import kr.wisestone.owl.service.*; import kr.wisestone.owl.util.*; import kr.wisestone.owl.util.DateUtil; import kr.wisestone.owl.vo.*; import kr.wisestone.owl.web.condition.*; import kr.wisestone.owl.web.form.*; import kr.wisestone.owl.web.view.ExcelView; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; import org.apache.poi.ss.usermodel.*; import org.jsoup.Jsoup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import static kr.wisestone.owl.domain.enumType.CustomFieldType.DATETIME; import static kr.wisestone.owl.domain.enumType.CustomFieldType.INPUT; @Service public class IssueServiceImpl extends AbstractServiceImpl> implements IssueService { private static final Logger log = LoggerFactory.getLogger(IssueServiceImpl.class); @Autowired private IssueRepository issueRepository; @Autowired private ProjectService projectService; @Autowired private IssueTableConfigService issueTableConfigService; @Autowired private IssueStatusService issueStatusService; @Autowired private IssueTypeService issueTypeService; @Autowired private PriorityService priorityService; @Autowired private SeverityService severityService; @Autowired private CustomFieldApiOverlapService customFieldApiOverlapService; @Autowired private IssueApiDefaultService issueApiDefaultService; @Autowired private ApiTokenService apiTokenService; @Autowired private CompanyFieldService companyFieldService; @Autowired private CompanyFieldCategoryService companyFieldCategoryService; @Autowired private IspFieldService ispFieldService; @Autowired private HostingFieldService hostingFieldService; @Autowired private CommonConfiguration configuration; @Autowired private IssueNumberGeneratorService issueNumberGeneratorService; @Autowired private AttachedFileService attachedFileService; @Autowired private IssueCustomFieldValueService issueCustomFieldValueService; @Autowired private IssueCompanyService issueCompanyService; @Autowired private IssueIspService issueIspService; @Autowired private IssueHostingService issueHostingService; @Autowired private IssueUserService issueUserService; @Autowired private IssueDepartmentService issueDepartmentService; @Autowired private CustomFieldService customFieldService; @Autowired private IssueTypeCustomFieldService issueTypeCustomFieldService; @Autowired private UserService userService; @Autowired private DepartmentService departmentService; @Autowired private IssueCommentService issueCommentService; @Autowired private IssueHistoryService issueHistoryService; @Autowired private ProjectRoleUserService projectRoleUserService; @Autowired private ProjectRoleDepartmentService projectRoleDepartmentService; @Autowired private IssueRiskService issueRiskService; @Autowired private WorkspaceService workspaceService; @Autowired private SystemEmailService systemEmailService; @Autowired private IssueVersionService issueVersionService; @Autowired private IssueReservationService issueReservationService; @Autowired private UserWorkspaceService userWorkspaceService; @Autowired private UserLevelService userLevelService; @Autowired private WorkflowDepartmentService workflowDepartmentService; @Autowired private IssueRelationService issueRelationService; @Autowired private IssueRelationRepository issueRelationRepository; @Autowired private ExcelView excelView; @Autowired private IssueMapper issueMapper; @Autowired private IssueCompanyRepository issueCompanyRepository; @Autowired private IssueIspRepository issueIspRepository; @Autowired private IssueHostingRepository issueHostingRepository; @Autowired private ExcelConditionCheck excelConditionCheck; @Autowired private SimpMessagingTemplate simpMessagingTemplate; @Autowired private UserDepartmentService userDepartmentService; @Autowired private UserDepartmentRepository userDepartmentRepository; @Autowired private DepartmentMapper departmentMapper; @Autowired private WorkflowDepartmentRepository workflowDepartmentRepository; @Autowired private IssueRelationMapper issueRelationMapper; @Autowired private WorkflowTransitionService workflowTransitionService; @Override protected JpaRepository getRepository() { return this.issueRepository; } private static final int EXCEL_DOWNLOAD_MAX_ROWS = 10000; // excel download 제한 private static final int EXCEL_IMPORT_MAX_ROWS = 10000; // excel import 제한 @Override @Transactional public void addIssueVersion(Long id) { Issue issue = this.getIssue(id); // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue); } @Override @Transactional public void addIssueVersion(Long id, Long userId) { Issue issue = this.getIssue(id); User user = this.userService.getUser(userId); // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue, user); } private IssueForm convertToIssueForm(IssueApiForm issueApiForm, User user) { if (issueApiForm.getIssueTypeId() == null) { throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR)); } IssueForm issueForm = ConvertUtil.copyProperties(issueApiForm, IssueForm.class); // issueForm.setFiles(issueApiForm.getFiles()); IssueType issueType = this.issueTypeService.getIssueType(issueApiForm.getIssueTypeId()); if (issueType == null){ throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR)); } Workflow workflow = issueType.getWorkflow(); if (issueApiForm.getApiType().equals(IssueApiForm.ApiType.add)) { // 이슈 상태가 지정되어 있지 않을 경우 워크플로우 대기 상태 값으로 지정 List departmentIds = this.workflowDepartmentService.findFirstDepartmentIds(workflow); if (departmentIds != null && departmentIds.size() > 0) { for (Long departmentId : departmentIds) { issueForm.addDepartmentId(departmentId); } } } else if (issueApiForm.getIssueStatusId() == null){ throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_ISSUE_STATUS_NOT_EXIST)); } else if (!this.workflowTransitionService.contains(issueApiForm.getIssueStatusId(), workflow.getId())) { //이슈 상태 유효성 확인 throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_ISSUE_STATUS_NOT_EXIST_IN_WORKFLOW)); } // 프로젝트 입력 Project project = issueType.getProject(); if (project == null){ throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR)); } issueForm.setProjectId(project.getId()); if (user != null) { // 기본값 입력하기 IssueApiDefaultForm issueApiDefaultForm = new IssueApiDefaultForm(); issueApiDefaultForm.setUserId(user.getId()); issueApiDefaultForm.setIssueTypeId(issueForm.getIssueTypeId()); IssueApiDefault issueApiDefault = this.issueApiDefaultService.find(issueApiDefaultForm); if (issueApiDefault != null) { ConvertUtil.copyProperties(issueApiDefault, issueForm); issueForm.setId(null); issueForm.setPriorityId(issueApiDefault.getPriority().getId()); issueForm.setSeverityId(issueApiDefault.getSeverity().getId()); } // 중복 값 상위 이슈의 하위 이슈로 처리하기 CustomFieldApiOverlapForm customFieldApiOverlapForm = new CustomFieldApiOverlapForm(); customFieldApiOverlapForm.setUserId(user.getId()); customFieldApiOverlapForm.setIssueTypeId(issueForm.getIssueTypeId()); // 상위일감에 사용할 중복값 설정 List customFieldApiOverlaps = this.customFieldApiOverlapService.find(user.getId(), issueApiForm.getIssueTypeId()); // if (customFieldApiOverlaps == null || customFieldApiOverlaps.size() == 0){ // throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_OVERLAP_SETTING_NOT_EXIST)); // } if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) { for (int i = 0; i < customFieldApiOverlaps.size(); i++) { CustomFieldApiOverlap customFieldApiOverlap = customFieldApiOverlaps.get(i); issueApiForm.addUseIssueCustomFieldId(customFieldApiOverlap.getCustomField().getId()); } // 종료상태가 아닌 중복된 상위 이슈검색 List issues = this.findIssue(issueApiForm, customFieldApiOverlaps, user.getId()); int size = issues.size(); if (size > 0) { Issue targetIssue = issues.get(0); if (targetIssue.getParentIssue() != null) { issueForm.setParentIssueId(targetIssue.getParentIssue().getId()); } else { issueForm.setParentIssueId(targetIssue.getId()); } } } issueForm.setIsApi(Issue.IS_API_YES); // 사용자 정의 필드 설정 issueForm.setIssueCustomFields(issueApiForm.getCustomFieldValues()); // 같은 도메인 업체 찾기 this.findCompanyField(issueForm); // api 입력값 적용 ConvertUtil.copyProperties(issueApiForm, issueForm); return issueForm; } else { throw new ApiAuthException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR)); } } private IssueForm findCompanyField(IssueForm issueForm) { if(issueForm.getIssueCustomFields() != null && issueForm.getIssueCustomFields().size() > 0) { CompanyFieldCondition condition = new CompanyFieldCondition(); List> companyFields = this.companyFieldService.find(condition); List> issueCompanyFields = Lists.newArrayList(); List> issueIspFields = Lists.newArrayList(); List> issueHostingFields = Lists.newArrayList(); for (Map issueCustomField : issueForm.getIssueCustomFields()) { Long customFieldId = MapUtil.getLong(issueCustomField, "customFieldId"); CustomField customField = this.customFieldService.getCustomField(customFieldId); if(customField != null && customField.getCustomFieldType().toString().equals("SITE") && customField.getName().equals("도메인")) { String useValue = issueCustomField.get("useValue").toString(); if(companyFields != null && companyFields.size() > 0) { for (Map companyField : companyFields) { CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class); if(companyFieldVo.getUrl() != null && useValue.equals(companyFieldVo.getUrl())) { companyField.put("companyId", companyField.get("id")); issueCompanyFields.add(companyField); if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) { Map ispField = this.ispFieldService.find(companyFieldVo.getIspId()); if (ispField != null) { ispField.put("ispId", ispField.get("id")); issueIspFields.add(ispField); } } if(companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) { Map hostingField = this.hostingFieldService.find(companyFieldVo.getHostingId()); if (hostingField != null) { hostingField.put("hostingId", hostingField.get("id")); issueHostingFields.add(hostingField); } } } } } } issueForm.setIssueCompanyFields(issueCompanyFields); issueForm.setIssueIspFields(issueIspFields); issueForm.setIssueHostingFields(issueHostingFields); } } return issueForm; } private User convertToUser(String token) { // 토큰으로 유저 정보 가져오기 UserVo userVo = this.apiTokenService.certification(token); // 해당 유저 정보가 현재 db에 있는지 확인 return this.userService.getUser(userVo.getId()); } // API 를 통해 이슈 추가. @Override @Transactional public List addApiIssue(IssueApiForm issueApiForm) throws CloneNotSupportedException { User user = convertToUser(issueApiForm.getToken()); IssueForm issueForm = this.convertToIssueForm(issueApiForm, user); List issues = Lists.newArrayList(); if (issueForm.getParentIssueId() != null // 기존 추가된 상위 일감이 없거나 설정된 중복 이슈 id가 없을때 || issueApiForm.getUseIssueCustomFieldIds().size() == 0) { issues.add(addIssue(user, issueForm, issueApiForm.getMultipartFiles())); } else { // 가상 상위 이슈 추가 IssueForm parentIssueForm = issueForm.clone(); // 가상 상위 이슈 추가 parentIssueForm.setUseIssueCustomFields(issueApiForm.getUseIssueCustomFieldIds()); // 같은 도메인 업체 찾기 IssueForm partners = this.findCompanyField(parentIssueForm); parentIssueForm.setIssueCompanyFields(partners.getIssueCompanyFields()); parentIssueForm.setIssueIspFields(partners.getIssueIspFields()); parentIssueForm.setIssueHostingFields(partners.getIssueHostingFields()); Issue issue = addIssue(user, parentIssueForm, null); issues.add(issue); // 하위 이슈 추가 issueForm.setParentIssueId(issue.getId()); issues.add(addIssue(user, issueForm, issueApiForm.getMultipartFiles())); } return issues; } // 상위 이슈 가져오기 private IssueVo getParentIssueVo(Long parentIssueId) { if (parentIssueId != null) { Issue parentIssue = this.getIssue(parentIssueId); return ConvertUtil.copyProperties(parentIssue, IssueVo.class); } return null; } // 중복된 상위 이슈 검색 private List findIssue(IssueApiForm issueApiform, List customFieldApiOverlaps, Long userId) { List issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues(); List resultIssueVos = Lists.newArrayList(); String comma = ","; if (issueCustomFieldValueForms.size() > 0) { String concatUseValue = ""; int useIdx = 0; IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator(); Collections.sort(issueCustomFieldValueForms, comp); List userValues = Lists.newArrayList(); for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) { userValues.add(issueCustomFieldValueForm.getUseValue()); for(CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) { if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) { if (useIdx > 0) { concatUseValue = concatUseValue.concat(comma); } concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue()); useIdx++; } } } IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition(); issueCustomFieldValueCondition.setUseValue(concatUseValue); issueCustomFieldValueCondition.setUseValues(userValues); issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId()); issueCustomFieldValueCondition.setIssueStatusType("CLOSE"); List> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); if (results != null && results.size() > 0) { for (Map result : results) { resultIssueVos.add(this.getIssue(MapUtil.getLong(result, "id"))); } } } return resultIssueVos; } // 이슈를 생성한다. @Override @Transactional public Issue addIssue(IssueForm issueForm, List multipartFiles) { User user = this.webAppUtil.getLoginUserObject(); return addIssue(user, issueForm, multipartFiles); } // 이슈를 생성한다. @Override @Transactional public Issue addIssue(User user, IssueForm issueForm, List multipartFiles) { StringBuilder detectIssueChange = new StringBuilder(); // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId()); // 프로젝트 유효성 체크 Project project = this.projectService.getProject(issueForm.getProjectId()); // 이슈 유형 유효성 체크 IssueType issueType = this.issueTypeService.getIssueType(issueForm.getIssueTypeId()); // 우선순위 유효성 체크 Priority priority = this.priorityService.getPriority(issueForm.getPriorityId()); // 중요도 유효성 체크 Severity severity = this.severityService.getSeverity(issueForm.getSeverityId()); // 제목 유효성 체크 this.verifyTitle(issueForm.getTitle()); // 날짜 유효성 체크 this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate()); // 담당 부서 유효성 체크 //this.verifyIssueDepartment(project, issueForm); // 이슈 상태 유형이 '대기' 인 이슈 상태 가져오기 IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow()); Issue issue = ConvertUtil.copyProperties(issueForm, Issue.class); issue.setProject(project); issue.setIssueStatus(issueStatus); issue.setIssueType(issueType); issue.setPriority(priority); issue.setSeverity(severity); if (issueForm.getParentIssueId() != null){ Issue parentIssue = this.getIssue(issueForm.getParentIssueId()); issue.setParentIssue(parentIssue); } issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project)); // 각 프로젝트의 고유 이슈 번호 생성 issue = this.issueRepository.saveAndFlush(issue); issue.setReverseIndex(issue.getId() * -1); // 쿼리 속도 개선을 위해 리버스 인덱스 생성 // 담당자 지정 //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds()); // 담당부서 지정 this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds()); // 업체 정보 저장 this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange); // ISP 정보 저장 this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange); // HOSTING 정보 저장 this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange); // 첨부 파일 저장 // multipartFile 을 file Map List 객체로 변경한다. List> convertFileMaps = this.convertMultipartFileToFile(multipartFiles); this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount()); // 텍스트 에디터에 첨부한 파일을 이슈와 연결 this.checkNotHaveIssueIdAttachedFile(issue, issueForm); // 사용자 정의 필드 저장 this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields()); // 이슈 이력 생성 this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null); // 이슈 위험 관리 생성 this.issueRiskService.addIssueRisk(issue, project.getWorkspace()); // 영속성 컨텍스트 비우기 this.clear(); // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. this.reservationIssueEmail(issue, EmailType.ISSUE_ADD); // 사용자 시스템 기능 사용 정보 수집 UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class); log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD)); return issue; } // 연관이슈를 생성한다. @Override @Transactional public Issue addRelIssue(IssueForm issueForm, List multipartFiles) { User user = this.webAppUtil.getLoginUserObject(); return addRelIssue(user, issueForm, multipartFiles); } // 하위이슈를 생성한다. @Override @Transactional public Issue addDownIssue(IssueForm issueForm, List multipartFiles) { User user = this.webAppUtil.getLoginUserObject(); return addDownIssue(user, issueForm, multipartFiles); } // 하위이슈를 생성한다. @Override @Transactional public Issue addDownIssue(User user, IssueForm issueForm, List multipartFiles) { StringBuilder detectIssueChange = new StringBuilder(); // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId()); // 프로젝트 유효성 체크 Project project = this.projectService.getProject(issueForm.getProjectId()); // 이슈 유형 유효성 체크 IssueType issueType = this.issueTypeService.getIssueType(issueForm.getIssueTypeId()); // 우선순위 유효성 체크 Priority priority = this.priorityService.getPriority(issueForm.getPriorityId()); // 중요도 유효성 체크 Severity severity = this.severityService.getSeverity(issueForm.getSeverityId()); // 제목 유효성 체크 this.verifyTitle(issueForm.getTitle()); // 날짜 유효성 체크 this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate()); // 담당 부서 유효성 체크 //this.verifyIssueDepartment(project, issueForm); // 이슈 상태 유형이 '대기' 인 이슈 상태 가져오기 IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow()); Issue issue = ConvertUtil.copyProperties(issueForm, Issue.class); issue.setProject(project); issue.setIssueStatus(issueStatus); issue.setIssueType(issueType); issue.setPriority(priority); issue.setSeverity(severity); if (issueForm.getParentIssueId() != null){ Issue parentIssue = this.getIssue(issueForm.getParentIssueId()); issue.setParentIssue(parentIssue); } issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project)); // 각 프로젝트의 고유 이슈 번호 생성 issue = this.issueRepository.saveAndFlush(issue); issue.setReverseIndex(issue.getId() * -1); // 쿼리 속도 개선을 위해 리버스 인덱스 생성 // 담당자 지정 //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds()); // 담당부서 지정 this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds()); // 업체 정보 저장 this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange); // ISP 정보 저장 this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange); // HOSTING 정보 저장 this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange); // 첨부 파일 저장 // multipartFile 을 file Map List 객체로 변경한다. List> convertFileMaps = this.convertMultipartFileToFile(multipartFiles); this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount()); // 텍스트 에디터에 첨부한 파일을 이슈와 연결 this.checkNotHaveIssueIdAttachedFile(issue, issueForm); // 사용자 정의 필드 저장 this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields()); // 이슈 이력 생성 this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null); // 이슈 위험 관리 생성 this.issueRiskService.addIssueRisk(issue, project.getWorkspace()); // 영속성 컨텍스트 비우기 this.clear(); // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. this.reservationIssueEmail(issue, EmailType.ISSUE_ADD); // 사용자 시스템 기능 사용 정보 수집 UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class); log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD)); return issue; } // 연관이슈를 생성한다. @Override @Transactional public Issue addRelIssue(User user, IssueForm issueForm, List multipartFiles) { StringBuilder detectIssueChange = new StringBuilder(); // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId()); // 프로젝트 유효성 체크 Project project = this.projectService.getProject(issueForm.getProjectId()); // 이슈 유형 유효성 체크 IssueType issueType = this.issueTypeService.getIssueType(issueForm.getIssueTypeId()); // 우선순위 유효성 체크 Priority priority = this.priorityService.getPriority(issueForm.getPriorityId()); // 중요도 유효성 체크 Severity severity = this.severityService.getSeverity(issueForm.getSeverityId()); // 제목 유효성 체크 this.verifyTitle(issueForm.getTitle()); // 날짜 유효성 체크 this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate()); // 담당 부서 유효성 체크 //this.verifyIssueDepartment(project, issueForm); // 이슈 상태 유형이 '대기' 인 이슈 상태 가져오기 IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow()); Issue issue = ConvertUtil.copyProperties(issueForm, Issue.class); issue.setProject(project); issue.setIssueStatus(issueStatus); issue.setIssueType(issueType); issue.setPriority(priority); issue.setSeverity(severity); if (issueForm.getParentIssueId() != null){ Issue parentIssue = this.getIssue(issueForm.getParentIssueId()); issue.setParentIssue(parentIssue); } issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project)); // 각 프로젝트의 고유 이슈 번호 생성 issue = this.issueRepository.saveAndFlush(issue); issue.setReverseIndex(issue.getId() * -1); // 쿼리 속도 개선을 위해 리버스 인덱스 생성 // 담당자 지정 //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds()); // 담당부서 지정 this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds()); // 업체 정보 저장 this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange); // ISP 정보 저장 this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange); // HOSTING 정보 저장 this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange); // 첨부 파일 저장 // multipartFile 을 file Map List 객체로 변경한다. List> convertFileMaps = this.convertMultipartFileToFile(multipartFiles); this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount()); // 텍스트 에디터에 첨부한 파일을 이슈와 연결 this.checkNotHaveIssueIdAttachedFile(issue, issueForm); // 사용자 정의 필드 저장 this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields()); // 이슈 이력 생성 this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null); // 이슈 위험 관리 생성 this.issueRiskService.addIssueRisk(issue, project.getWorkspace()); // 영속성 컨텍스트 비우기 this.clear(); // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. this.reservationIssueEmail(issue, EmailType.ISSUE_ADD); // 사용자 시스템 기능 사용 정보 수집 UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class); log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD)); return issue; } // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. private void reservationIssueEmail(Issue issue, EmailType emailType) { Map issueMap = new HashMap<>(); // 이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다. this.makeIssueMapToIssue(issue, issueMap); Map projectRoleUserMap = new HashMap<>(); projectRoleUserMap.put("id", issue.getProject().getId()); projectRoleUserMap.put("statuses", Lists.newArrayList("02")); // 관리자 조회 // 관리자 정보 셋팅 List> projectRoleUsers = this.projectRoleUserService.findProjectRoleUser(projectRoleUserMap); if (projectRoleUsers != null && !projectRoleUsers.isEmpty()) { for (Map projectRoleUser : projectRoleUsers) { UserVo userVo = ConvertUtil.convertMapToClass(projectRoleUser, UserVo.class); // 이슈 생성 알림 메일 전송 this.systemEmailService.reservationEmail(new String[]{userVo.getAccount()}, emailType, issueMap); } } } // 이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다. public void makeIssueMapToIssue(Issue issue, Map issueMap) { issueMap.put("title", issue.getTitle()); issueMap.put("issueNumber", issue.getIssueNumber()); issueMap.put("issueTypeName", issue.getIssueType().getName()); issueMap.put("issueStatusName", issue.getIssueStatus().getName()); // 담당자 StringBuilder assigneeBuilder = new StringBuilder(); for (IssueUser issueUser : issue.getIssueUsers()) { assigneeBuilder.append(issueUser.getUser().getName()); assigneeBuilder.append("("); assigneeBuilder.append(CommonUtil.decryptAES128(issueUser.getUser().getAccount())); assigneeBuilder.append(")"); assigneeBuilder.append("\n"); } issueMap.put("assignees", assigneeBuilder.toString()); // 담당부서 StringBuilder departsBuilder = new StringBuilder(); for (IssueDepartment issueDepartment : issue.getIssueDepartments()) { departsBuilder.append(issueDepartment.getDepartment().getDepartmentName()); departsBuilder.append("\n"); } issueMap.put("departments", departsBuilder.toString()); // 기간 if (!StringUtils.isEmpty(issue.getStartDate())) { issueMap.put("period", issue.getStartDate() + " ~ " + issue.getCompleteDate()); } issueMap.put("severityName", issue.getSeverity().getName()); issueMap.put("priorityName", issue.getPriority().getName()); issueMap.put("projectName", issue.getProject().getName()); issueMap.put("projectKey", issue.getProject().getProjectKey()); User user = this.userService.getUser(issue.getRegisterId()); StringBuilder registerBuilder = new StringBuilder(); registerBuilder.append(user.getName()); registerBuilder.append("("); registerBuilder.append(CommonUtil.decryptAES128(user.getAccount())); registerBuilder.append(")"); issueMap.put("register", registerBuilder.toString()); Map customField = new HashMap<>(); List issueCustomFieldValueVos = this.issueCustomFieldValueService.findByIssueId(issue.getId()); for (IssueCustomFieldValueVo issueCustomFieldValueVo : issueCustomFieldValueVos) { // 이미 데이터가 존재 if (customField.get(issueCustomFieldValueVo.getCustomFieldVo().getName()) != null) { List useValues = (List) customField.get(issueCustomFieldValueVo.getCustomFieldVo().getName()); useValues.add(issueCustomFieldValueVo.getUseValue()); customField.put(issueCustomFieldValueVo.getCustomFieldVo().getName(), useValues); } else { if (issueCustomFieldValueVo.getCustomFieldVo().getCustomFieldType().equals(INPUT.toString())) { customField.put(issueCustomFieldValueVo.getCustomFieldVo().getName(), issueCustomFieldValueVo.getUseValue()); } else { customField.put(issueCustomFieldValueVo.getCustomFieldVo().getName(), Lists.newArrayList(issueCustomFieldValueVo.getUseValue())); } } } List> customFields = Lists.newArrayList(); Iterator iterator = customField.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); Map result = new HashMap<>(); result.put("name", key); result.put("useValue", customField.get(key)); customFields.add(result); } issueMap.put("customFields", customFields); issueMap.put("description", issue.getDescription()); //업체,ISP,HOSTING 추가 StringBuilder attachedFileBuilder = new StringBuilder(); List attachedFiles = this.attachedFileService.findByIssueId(issue.getId()); for (AttachedFile attachedFile : attachedFiles) { attachedFileBuilder.append(""); attachedFileBuilder.append(attachedFile.getName()); attachedFileBuilder.append(""); attachedFileBuilder.append("\n"); } issueMap.put("attachedFiles", attachedFileBuilder.toString()); } // 제목 유효성 체크 private void verifyTitle(String title) { if (StringUtils.isEmpty(title)) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NO_TITLE)); } if (title.length() > 300) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_TITLE_MAX_LENGTH_OUT)); } } /** * 날짜 유효성 체크 * @param startDate 시작 일자(문자) * @param completeDate 종료 일자(문자) */ private void checkStartCompleteDate(String startDate, String completeDate) { if (!StringUtils.isEmpty(startDate) && !StringUtils.isEmpty(completeDate)) { Date start = DateUtil.convertStrToDate(startDate, "yy-MM-dd"); Date end = DateUtil.convertStrToDate(completeDate, "yy-MM-dd"); checkStartCompleteDate(start, end); } } /** * 날짜 유효성 체크 * @param start 시작 일자 * @param end 종료 일자 */ private void checkStartCompleteDate(Date start, Date end) { if (start.getTime() > end.getTime()) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.DATE_PICKER_NOT_AVAILABLE)); } } // 텍스트 에디터에 첨부한 파일을 이슈와 연결 private void checkNotHaveIssueIdAttachedFile(Issue issue, IssueForm issueForm) { if (!issueForm.getAttachedFileIds().isEmpty()) { this.attachedFileService.connectIssueIdAttachedFile(issue, issueForm); } } void SetMyDepartmentId(IssueCondition issueCondition){ Long loginId = issueCondition.getLoginUserId(); List myDepartmentIds = Lists.newArrayList(); List myDepartments = this.userDepartmentRepository.findByUserId(loginId); if(myDepartments != null && myDepartments.size() > 0){ for(UserDepartment myDepartment : myDepartments){ myDepartmentIds.add(myDepartment.getDepartmentId()); } } else { myDepartmentIds.add(-1L); } issueCondition.setMyDepartmentIds(myDepartmentIds); } void SetAllDepartmentId(IssueCondition issueCondition){ List departmentIds = Lists.newArrayList(); List> departmentList = this.departmentMapper.find(null); if(departmentList != null && departmentList.size() > 0){ for(Map department : departmentList){ departmentIds.add((Long) department.get("id")); } } issueCondition.setMyDepartmentIds(departmentIds); } void SetWorkflowDepartment(List issueVos){ for(IssueVo issueVo : issueVos){ Long issueTypeId = issueVo.getIssueTypeId(); IssueType issueType = this.issueTypeService.getIssueType(issueTypeId); Long workflowId = issueType.getWorkflow().getId(); List workflowDepartmentList = this.workflowDepartmentRepository.findByWorkflowId(workflowId); List workflowDepartmentIds = Lists.newArrayList(); if(workflowDepartmentList != null && workflowDepartmentList.size()>0){ for(WorkflowDepartment workflowDepartment : workflowDepartmentList){ workflowDepartmentIds.add(workflowDepartment.getDepartment().getId()); } } if(issueVo.getIssueTypeId().equals(issueTypeId)){ issueVo.setWorkflowDepartmentIds(workflowDepartmentIds); } } } // 이슈 목록을 조회한다. @Override @Transactional(readOnly = true) public List findIssue(Map resJsonData, IssueCondition issueCondition, Pageable pageable) { // 검색 조건을 만든다 if (!this.makeIssueSearchCondition(issueCondition, Lists.newArrayList("01", "02", "03"), pageable)) { // 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다. this.notFoundIssueList(resJsonData, pageable); return Lists.newArrayList(); } Set issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션 // 사용자 정의 필드를 사용한 이슈를 찾는다. 만약 이슈가 없다면 여기서 이슈 조회가 끝난다. if (!this.searchUseCustomFields(issueCondition, issueIds, resJsonData, pageable)) { // 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다. this.notFoundIssueList(resJsonData, pageable); return Lists.newArrayList(); } List issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션 // 사용자 정의 필드로 검색한 이슈 아이디 값 List issueKeys = Lists.newArrayList(issueIds); issueCondition.setIssueIds(issueKeys); User user = this.webAppUtil.getLoginUserObject(); issueCondition.setLoginUserId(user.getId()); issueCondition.setWorkspaceId(user.getLastWorkspaceId()); List> results = Lists.newArrayList(); Long totalCount = 0L; // UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId()); // if (!this.userWorkspaceService.checkWorkspaceManager(user) // && !MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE)) { //최고관리자 & 프로젝트,이슈 관리자 일 경우 모든 이슈 보기 // this.SetMyDepartmentId(issueCondition); //this.SetAllDepartmentId(issueCondition); // } /*else{ // results = this.issueMapper.findByDepartment(issueCondition); // totalCount = this.issueMapper.countByDepartment(issueCondition); // }*/ // StopWatch serviceStart = new StopWatch(); // serviceStart.start(); results = this.issueMapper.find(issueCondition); // serviceStart.stop(); // log.error("result : " + serviceStart.toString()); // serviceStart = new StopWatch(); // serviceStart.start(); totalCount = this.issueMapper.count(issueCondition); // serviceStart.stop(); // log.error("totalCount : " + serviceStart.toString()); int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1; // 이슈 아이디 초기화 issueCondition.setIsApi(issueCondition.getIsApi()); issueCondition.setIssueIds(Lists.newArrayList()); // Map 에 있는 데이터를 IssueVo 데이터로 변환한다. this.setMapToIssueVo(results, issueVos, issueCondition, user); if (issueCondition.getTree()) { this.setParentIssue(issueVos); this.setDownIssues(user, issueVos); this.setRelationIssues(issueVos); } this.setCountDownIssues(issueVos); this.SetWorkflowDepartment(issueVos); //워크플로우에 설정한 담당부서 가져오기 resJsonData.put(Constants.RES_KEY_CONTENTS, issueVos); resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(), totalPage, totalCount)); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_FIND)); return issueVos; } // 하위 이슈 세팅(재귀) private void setDownIssues(User user, List issueVos) { for(IssueVo issueVo : issueVos) { List downIssues = this.issueRepository.findByParentIssueId(issueVo.getId()); List downIssueVos = Lists.newArrayList(); IssueCondition issueCondition = new IssueCondition(); issueCondition.addIssueIds(String.valueOf(issueVo.getId())); for(Issue downIssue : downIssues){ IssueVo addIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class); addIssueVo.setIssueTypeId(downIssue.getIssueType().getId()); downIssueVos.add(addIssueVo); } issueVo.setIssueDownVos(downIssueVos); if (downIssueVos.size() > 0) { this.setDownIssues(user, downIssueVos); } // 이슈 사용자 정보 추가 //this.setIssueUserList(issueVos, issueCondition); this.setIssueDepartmentList(issueVos, issueCondition, user); // 등록자 정보 추가 this.setRegister(issueVos); // 담당자 정보 셋팅 // 사용자 정의 필드 정보 추가 this.setIssueCustomFieldValue(issueVos, issueCondition); //워크플로우에 설정한 담당부서 가져오기 this.SetWorkflowDepartment(issueVos); } } // 연관 이슈 세팅 private void setRelationIssues(List issueVos) { for(IssueVo issueVo : issueVos) { List relationIssues = this.issueRelationService.findRelationIssue(issueVo.getId()); for(IssueVo relationIssue : relationIssues){ issueVo.addRelationIssueVo(ConvertUtil.copyProperties(relationIssue, IssueVo.class)); } } } // 상위 이슈 체크 private void setParentIssue(List issueVos) { for(IssueVo issueVo : issueVos) { if(issueVo.getParentIssueId() != null) { Issue parentIssue = this.getIssue(issueVo.getParentIssueId()); //issueVo.setParentIssueVo(ConvertUtil.copyProperties(parentIssue, IssueVo.class)); if(parentIssue.getIssueCustomFieldValues() == null || parentIssue.getIssueCustomFieldValues().size() == 0){ issueVo.setIssueCustomFieldValueVos(null); } ConvertUtil.copyProperties(parentIssue, issueVo); } } } @Override @Transactional(readOnly = true) public void setCountDownIssues(List issueVos) { for (IssueVo issueVo : issueVos){ List downIssues = this.issueRepository.findByParentIssueId(issueVo.getId()); //하위이슈 가져오기 if(downIssues != null && downIssues.size() > 0){ //상위이슈 가지고 있는 애들이 있으면 int downIssueAllCount = 0;// 하위이슈 전체 카운트 int downIssueCount = 0;// 하위이슈 미완료 카운트 for(Issue downIssue : downIssues){ downIssueAllCount ++; Long parentIssueId = downIssue.getParentIssue().getId(); Issue parentIssue = this.getIssue(parentIssueId); IssueVo parentIssueVo = ConvertUtil.copyProperties(parentIssue, IssueVo.class); parentIssueVo.setDownIssueAllCount(downIssueAllCount); IssueStatus downIssueStatus = this.issueStatusService.getIssueStatus(downIssue.getIssueStatus().getId()); IssueVo downIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class); downIssueVo.setIssueStatusType(downIssueStatus.getIssueStatusType().toString()); if(!downIssueVo.getIssueStatusType().equals("CLOSE")){ //미완료 하위이슈 체크 downIssueCount ++; } issueVo.setDownIssueCount(downIssueCount); issueVo.setDownIssueAllCount(parentIssueVo.getDownIssueAllCount()); } } } } // 이슈 목록을 조회한다(차트용 - 연관일감포함) @Override @Transactional(readOnly = true) public void findApiIssue(ApiMonitorCondition apiMonitorCondition, Map resJsonData) { IssueTypeCondition issueTypeCondition = new IssueTypeCondition(); issueTypeCondition.setIsApi(Issue.IS_API_YES); List issueTypes = this.issueTypeService.findIssueType(issueTypeCondition); // 검색 일자를 구한다. List searchDates = Lists.newArrayList(); if (apiMonitorCondition.getSearchPeriod().equals(DateUtil.CUSTOM_INPUT)) { Date startDate = DateUtil.convertStrToDate(apiMonitorCondition.getSearchStartDate(), "yyyy-MM-dd"); Date endDate = DateUtil.addDays(DateUtil.convertStrToDate(apiMonitorCondition.getSearchEndDate(), "yyyy-MM-dd"), 1); searchDates = CommonUtil.findSearchPeriod(startDate, endDate); } else { searchDates = CommonUtil.findSearchPeriod(apiMonitorCondition.getSearchPeriod()); } // 날짜가 검색되지 않았으면 오류 if (searchDates.size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.WIDGET_SEARCH_DATE_NOT_FOUND)); } Long index = 1L; List apiMonitorVos = Lists.newArrayList(); for (Date date : searchDates) { String onlyDate = DateUtil.convertDateToYYYYMMDD(date); issueTypeCondition.setStartDate(onlyDate + " 00:00:00"); issueTypeCondition.setEndDate(onlyDate + " 23:59:59"); ApiMonitorVo apiMonitorVo = new ApiMonitorVo(); apiMonitorVo.setId(index); for (IssueTypeVo issueTypeVo : issueTypes) { issueTypeCondition.setId(issueTypeVo.getId()); apiMonitorVo.addIssueTypeCount(this.issueMapper.countByIssueTypeIdAndDate(issueTypeCondition)); apiMonitorVo.setIsApi(Issue.IS_API_YES); apiMonitorVos.add(apiMonitorVo); } index++; } Map data = new HashMap<>(); data.put("issueTypeVos", issueTypes); data.put("apiMonitorVos", apiMonitorVos); resJsonData.put(Constants.RES_KEY_CONTENTS, data); } // 이슈 목록을 조회한다(차트용 - 연관일감포함) @Override @Transactional(readOnly = true) public List findChartIssue(Map resJsonData, IssueCondition issueCondition, Pageable pageable) { // 검색 조건을 만든다 if (!this.makeIssueSearchCondition(issueCondition,Lists.newArrayList("01", "02", "03"), pageable)) { // 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다. this.notFoundIssueList(resJsonData, pageable); return Lists.newArrayList(); } Set issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션 // 사용자 정의 필드를 사용한 이슈를 찾는다. 만약 이슈가 없다면 여기서 이슈 조회가 끝난다. if (!this.searchUseCustomFields(issueCondition, issueIds, resJsonData, pageable)) { // 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다. this.notFoundIssueList(resJsonData, pageable); return Lists.newArrayList(); } // 튜닝 전 - 1.3 / 1.2 / 1.1 // 튜닝 후 (단일/다중 검색 조건 3개 기준) - 0.49 / 0.41 / 0.47 / 0.41 List issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션 // 사용자 정의 필드로 검색한 이슈 아이디 값 List issueKeys = Lists.newArrayList(issueIds); issueCondition.setIssueIds(issueKeys); List> results = this.issueMapper.find(issueCondition); int totalCount = results.size(); int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1; // 이슈 아이디 초기화 issueCondition.setIssueIds(Lists.newArrayList()); // Map 에 있는 데이터를 IssueVo 데이터로 변환한다. this.setMapToIssueVoForChart(results, issueVos, issueCondition); resJsonData.put(Constants.RES_KEY_CONTENTS, issueVos); resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(), totalPage, totalCount)); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_FIND)); return issueVos; } // 이슈 목록을 조회한다(차트용 - 연관일감) @Override @Transactional(readOnly = true) public List findChartIssue(Map resJsonData, ProjectCondition projectCondition, Pageable pageable) { IssueCondition issueCondition = new IssueCondition(); // 검색 조건을 만든다 User user = this.webAppUtil.getLoginUserObject(); if (!this.makeIssueSearchCondition(user, issueCondition, projectCondition, pageable)) { // 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다. this.notFoundIssueList(resJsonData, pageable); return Lists.newArrayList(); } Set issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션 List issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션 // 사용자 정의 필드로 검색한 이슈 아이디 값 List issueKeys = Lists.newArrayList(issueIds); issueCondition.setIssueIds(issueKeys); List> results = this.issueMapper.find(issueCondition); int totalCount = results.size(); int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1; // 이슈 아이디 초기화 issueCondition.setIssueIds(Lists.newArrayList()); // Map 에 있는 데이터를 IssueVo 데이터로 변환한다. this.setMapToIssueVoForChart(results, issueVos, issueCondition); resJsonData.put(Constants.RES_KEY_CONTENTS, issueVos); resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(), totalPage, totalCount)); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_FIND)); return issueVos; } // Map 에 있는 데이터를 IssueVo 데이터로 변환한다. 차트용 private void setMapToIssueVoForChart(List> results, List issueVos, IssueCondition issueCondition) { for (Map result : results) { IssueVo issueVo = ConvertUtil.convertMapToClass(result, IssueVo.class); issueVos.add(issueVo); issueCondition.addIssueIds(String.valueOf(issueVo.getId())); } for (IssueVo issueVo : issueVos) { this.setRelationIssue(issueVo, issueVo.getId()); } } // Map 에 있는 데이터를 IssueVo 데이터로 변환한다. private void setMapToIssueVo(List> results, List issueVos, IssueCondition issueCondition, User user) { for (Map result : results) { IssueVo issueVo = ConvertUtil.convertMapToClass(result, IssueVo.class); issueVos.add(issueVo); issueCondition.addIssueIds(String.valueOf(issueVo.getId())); } // 이슈 사용자 정보 추가 //this.setIssueUserList(issueVos, issueCondition); this.setIssueDepartmentList(issueVos, issueCondition, user); // 등록자 정보 추가 this.setRegister(issueVos); // 담당자 정보 셋팅 // 사용자 정의 필드 정보 추가 this.setIssueCustomFieldValue(issueVos, issueCondition); } // 검색 조건을 만든다 private boolean makeIssueSearchCondition(IssueCondition condition, List projectStatues, Pageable pageable) { if (pageable != null) { condition.setPage(pageable.getPageNumber() * pageable.getPageSize()); condition.setPageSize(pageable.getPageSize()); } condition.setLoginUserId(this.webAppUtil.getLoginId()); condition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId()); User user = this.webAppUtil.getLoginUserObject(); UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId()); // 프로젝트 키가 존재할 경우 프로젝트 키에 해당하는 프로젝트를 조회하고 검색 조건에 셋팅한다. if (!this.getProjectByProjectKey(condition.getProjectKey(), condition)) { return false; } // 프로젝트를 선택하지 않았으면 해당 업무 공간에서 참여하고 있는 프로젝트를 찾는다. if (condition.getProjectIds().size() < 1) { List> projects = Lists.newArrayList(); if (this.userWorkspaceService.checkWorkspaceManager(user) || MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT)){ return true; }/*else if (MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE)){ projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectStatues, condition.getProjectType()); }*/ else { projects = this.projectService.findByWorkspaceIdAndIncludeProject(projectStatues, condition.getProjectType()); } List projectIds = Lists.newArrayList(); for (Map result : projects) { Long projectId = MapUtil.getLong(result, "id"); if (projectId != null) { projectIds.add(projectId); } } condition.setProjectIds(projectIds); if (projectIds.size() < 1) { return false; } } return true; } // 검색 조건을 만든다 private boolean makeIssueSearchCondition(User user, IssueCondition condition, ProjectCondition projectCondition, Pageable pageable) { if (pageable != null) { condition.setPage(pageable.getPageNumber() * pageable.getPageSize()); condition.setPageSize(pageable.getPageSize()); } condition.setLoginUserId(this.webAppUtil.getLoginId()); condition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId()); projectCondition.setWorkspaceId(condition.getWorkspaceId()); // 프로젝트 키가 존재할 경우 프로젝트 키에 해당하는 프로젝트를 조회하고 검색 조건에 셋팅한다. if (!this.getProjectByProjectKey(condition.getProjectKey(), condition)) { return false; } // 프로젝트를 선택하지 않았으면 해당 업무 공간에서 참여하고 있는 프로젝트를 찾는다. if (condition.getProjectIds().size() < 1) { List> projects = null; UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId()); if (this.userWorkspaceService.checkWorkspaceManager(user) || (MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT) && MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE))) { projects = this.projectMapper.findByWorkspaceManagerAll(projectCondition); } else { projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectCondition); } List projectIds = Lists.newArrayList(); for (Map result : projects) { Long projectId = MapUtil.getLong(result, "id"); if (projectId != null) { projectIds.add(projectId); } } condition.setProjectIds(projectIds); if (projectIds.size() < 1) { return false; } } return true; } // 프로젝트 키가 존재할 경우 프로젝트 키에 해당하는 프로젝트를 조회하고 검색 조건에 셋팅한다. private boolean getProjectByProjectKey(String projectKey, IssueCondition condition) { if (!StringUtils.isEmpty(projectKey)) { Project project = this.projectService.findByProjectKey(projectKey); if (project != null) { // 이미 프로젝트를 선택했을 경우에 프로젝트키로 검색한 프로젝트가 포함되어 있지 않으면 false if (condition.getProjectIds().size() > 0) { if (condition.getProjectIds().contains(project.getId())) { condition.setProjectIds(Lists.newArrayList()); } else { return false; } } condition.addProjectIds(project.getId()); } else { return false; } } return true; } // 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다. private void notFoundIssueList(Map resJsonData, Pageable pageable) { resJsonData.put(Constants.RES_KEY_CONTENTS, Lists.newArrayList()); resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(), 0, 0)); } // 사용자 정의 필드를 사용한 이슈를 찾는다. 만약 이슈가 없다면 여기서 이슈 조회가 끝난다. private boolean searchUseCustomFields(IssueCondition condition, Set issueIds, Map resJsonData, Pageable pageable) { // 사용자 정의 필드 값이 검색 옵션으로 있었을 때 조회된 이슈가 없으면 조회를 더 이상 할 필요가 없다. // 사용자 정의 필드를 사용한 이슈를 찾는다. boolean customFieldSearch = this.issueCustomFieldValueService.find(condition, issueIds); // 사용자 정의 필드 값이 존재하여 검색을 했을 때 검색된 이슈가 없으면 여기서 종료한다. if (customFieldSearch && issueIds.size() < 1) { resJsonData.put(Constants.RES_KEY_CONTENTS, Lists.newArrayList()); if (pageable != null) { resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(), 0, 0)); } return false; } return true; } // 이슈 담당자 정보를 셋팅한다. private void setIssueUserList(List issueVos, IssueCondition issueCondition, User user) { if (issueVos.size() < 1) { return; } List> issueUsers = this.issueMapper.findIssueUser(issueCondition); Map issueConverterUsers = new HashMap<>(); // 이슈에 해당하는 이슈 담당자 정보 셋팅 for (Map issueUser : issueUsers) { String issueId = MapUtil.getString(issueUser, "issueId"); if (MapUtil.getObject(issueConverterUsers, issueId) != null) { List users = (List) MapUtil.getObject(issueConverterUsers, issueId); users.add(new UserVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "name"), CommonUtil.decryptAES128(MapUtil.getString(issueUser, "account")), MapUtil.getString(issueUser, "profile"))); } else { List users = Lists.newArrayList(new UserVo(MapUtil.getLong(issueUser, "id"), MapUtil.getString(issueUser, "name"), CommonUtil.decryptAES128(MapUtil.getString(issueUser, "account")), MapUtil.getString(issueUser, "profile"))); issueConverterUsers.put(issueId, users); } } // 이슈Vo에 담당자 정보를 셋팅 for (IssueVo issueVo : issueVos) { if (MapUtil.getObject(issueConverterUsers, String.valueOf(issueVo.getId())) != null) { List userVos = (List) MapUtil.getObject(issueConverterUsers, String.valueOf(issueVo.getId())); issueVo.setUserVos(userVos); } // 이슈 수정 권한을 갖고 있는지 확인 if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user, null)) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } } } // 이슈 담당부서 정보를 셋팅한다. private void setIssueDepartmentList(List issueVos, IssueCondition issueCondition, User user) { if (issueVos.size() < 1) { return; } List> issueDepartments = this.issueMapper.findIssueDepartment(issueCondition); Map issueConverterDepartments = new HashMap<>(); // 이슈에 해당하는 이슈 담당부서 정보 셋팅 for (Map issueDepartment : issueDepartments) { String issueId = MapUtil.getString(issueDepartment, "issueId"); if (MapUtil.getObject(issueConverterDepartments, issueId) != null) { List departments = (List) MapUtil.getObject(issueConverterDepartments, issueId); departments.add(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription"))); } else { List departments = Lists.newArrayList(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription"))); issueConverterDepartments.put(issueId, departments); } } // 이슈Vo에 담당부서 정보를 셋팅 for (IssueVo issueVo : issueVos) { if (MapUtil.getObject(issueConverterDepartments, String.valueOf(issueVo.getId())) != null) { List departmentVos = (List) MapUtil.getObject(issueConverterDepartments, String.valueOf(issueVo.getId())); issueVo.setDepartmentVos(departmentVos); } // 이슈 수정 권한을 갖고 있는지 확인 if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user, issueVo.getDepartmentVos())) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } } } // 이슈 상세 정보를 조회한다. @Override @Transactional(readOnly = true) public void detailIssue(Map resJsonData, IssueCondition issueCondition) { IssueVo issueVo = new IssueVo(); Pageable relPageable = issueCondition.getRelPageable(); Pageable downPageable = issueCondition.getDownPageable(); if (issueCondition.getId() != null) { Issue issue = this.getIssue(issueCondition.getId()); issueVo = ConvertUtil.copyProperties(issue, IssueVo.class); User user = this.webAppUtil.getLoginUserObject(); if (relPageable != null) { issueVo.setRelPageNumber(relPageable.getPageNumber()); issueVo.setRelPageSize(relPageable.getPageSize()); issueVo.setRelPage(relPageable.getPageNumber() * relPageable.getPageSize()); } if (downPageable != null) { issueVo.setDownPageNumber(downPageable.getPageNumber()); issueVo.setDownPage(downPageable.getPageNumber() * downPageable.getPageSize()); issueVo.setDownPageSize(downPageable.getPageSize()); } switch (issueCondition.getDeep()) { case "01": // 프로젝트, 이슈 유형, 이슈 상태, 우선순위, 중요도, 담당부서, 첨부파일, 사용자 정의 필드 정보를 셋팅한다. issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class)); issueVo.setIssueTypeVo(ConvertUtil.copyProperties(issue.getIssueType(), IssueTypeVo.class)); issueVo.setIssueStatusVo(ConvertUtil.copyProperties(issue.getIssueStatus(), IssueStatusVo.class)); issueVo.setPriorityVo(ConvertUtil.copyProperties(issue.getPriority(), PriorityVo.class)); issueVo.setSeverityVo(ConvertUtil.copyProperties(issue.getSeverity(), SeverityVo.class)); this.setRegister(issue, issueVo); // 등록자 정보 셋팅 //this.setIssueUser(issue, issueVo); // 담당자 정보 셋팅 this.setIssueDepartment(issue, issueVo); // 담당부서 정보 셋팅 this.setAttachedFiles(issue, issueVo); // 첨부 파일 정보 셋팅 this.setIssueCustomFields(issue, issueVo); // 사용자 정의 필드 값 정보 셋팅 this.setRelationIssue(issue, issueVo); //연관 일감 셋팅 this.setDownIssues(issue, issueVo); //하위 이슈 세팅 break; case "02": // 프로젝트, 이슈 유형, 이슈 상태, 우선순위, 중요도, 담당자, 첨부파일, 사용자 정의 필드 정보, 댓글, 기록을 셋팅한다. this.setIssueDetail(issueVo, issue, user); // 이슈 상세 정보를 셋팅한다. this.setIssueTableConfigs(issue, issueVo, issueCondition); issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class)); break; } } // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_DETAIL)); resJsonData.put(Constants.RES_KEY_CONTENTS, issueVo); } // 테이블 설정 셋팅 private void setIssueTableConfigs(Issue issue, IssueVo issueVo, IssueCondition issueCondition) { //Long IssueTypeId = issue.getIssueType().getId(); Long IssueTypeId = issueCondition.getIssueTypeId(); for (int tableConfigType : IssueTableConfig.IssueTableTypes) { if (tableConfigType != IssueTableConfig.ISSUE_TABLE_TYPE_MAIN) { issueVo.addIssueTableConfigVo(createIssueTableConfigVo(IssueTypeId, tableConfigType)); } } } private IssueTableConfigVo createIssueTableConfigVo(Long issueTypeId, int tableConfigType) { IssueTableConfig issueTableConfig = this.issueTableConfigService.findByUserIdAndWorkspaceIdAndIssueTypeIdAndIssueTableType(issueTypeId, tableConfigType); if (issueTableConfig != null) { return ConvertUtil.copyProperties(issueTableConfig, IssueTableConfigVo.class); } return new IssueTableConfigVo(); } // 하위 이슈 정보를 셋팅한다 private void setDownIssues(Issue issue, IssueVo issueVo) { Page downIssues = null; List downIssueList = this.issueRepository.findByParentIssueId(issue.getId()); if(downIssueList != null && downIssueList.size() > 0) { int startPage = 0; if (issueVo.getDownPage() != 0) { startPage = (int) Math.floor(issueVo.getDownPage()/issueVo.getDownPageSize()); } Pageable pageable = PageRequest.of(startPage, issueVo.getDownPageSize()); downIssues = this.issueRepository.findByParentIssueId(issue.getId(), pageable); } if(downIssues != null){ issueVo.setDownTotalPage(downIssues.getTotalPages()); issueVo.setDownTotalCount(downIssues.getTotalElements()); List resultList = new ArrayList<>(); for(Issue downIssue : downIssues){ IssueVo downIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class); downIssueVo.setIssueTypeVo(ConvertUtil.copyProperties(downIssue.getIssueType(), IssueTypeVo.class)); downIssueVo.setPriorityVo(ConvertUtil.copyProperties(downIssue.getPriority(), PriorityVo.class)); downIssueVo.setSeverityVo(ConvertUtil.copyProperties(downIssue.getSeverity(), SeverityVo.class)); //이슈 상태 추가 IssueStatusVo issueStatusVo = ConvertUtil.copyProperties(downIssue.getIssueStatus(), IssueStatusVo.class, "issueStatusType"); issueStatusVo.setIssueStatusType(downIssue.getIssueStatus().getIssueStatusType().toString()); downIssueVo.setIssueStatusVo(issueStatusVo); this.setRegister(downIssue, downIssueVo); // 등록자 this.setIssueDepartment(downIssue, downIssueVo); // 담당부서 정보 셋팅 this.setIssueCustomFields(downIssue, downIssueVo); // 사용자정의필드 정보 세팅 this.setIssueHistory(downIssue, downIssueVo); // 이슈 기록 정보 셋팅 this.setIssueComments(downIssue, downIssueVo); // 댓글 정보 셋팅 this.setIssueCompanyField(downIssue, downIssueVo); //업체 정보 세팅 this.setIssueIspField(downIssue, downIssueVo); //ISP 정보 세팅 this.setIssueHostingField(downIssue, downIssueVo); //HOSTING 정보 세팅 downIssueVo.setModifyPermissionCheck(issueVo.getModifyPermissionCheck()); resultList.add(downIssueVo); } issueVo.setIssueDownVos(resultList); } } // 이슈 상세 정보를 셋팅한다. @Override @Transactional(readOnly = true) public void setIssueDetail(IssueVo issueVo, Issue issue, User user) { // 이슈 수정 권한을 갖고 있는지 확인 if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user, issueVo.getDepartmentVos())) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class)); issueVo.setIssueTypeVo(ConvertUtil.copyProperties(issue.getIssueType(), IssueTypeVo.class)); IssueStatusVo issueStatusVo = ConvertUtil.copyProperties(issue.getIssueStatus(), IssueStatusVo.class, "issueStatusType"); issueStatusVo.setIssueStatusType(issue.getIssueStatus().getIssueStatusType().toString()); issueVo.setIssueStatusVo(issueStatusVo); issueVo.setPriorityVo(ConvertUtil.copyProperties(issue.getPriority(), PriorityVo.class)); issueVo.setSeverityVo(ConvertUtil.copyProperties(issue.getSeverity(), SeverityVo.class)); this.setRegister(issue, issueVo); // 등록자 정보 셋팅 //this.setIssueUser(issue, issueVo); // 담당자 정보 셋팅 this.setIssueDepartment(issue, issueVo); // 담당부서 정보 셋팅 this.setAttachedFiles(issue, issueVo); // 첨부 파일 정보 셋팅 this.setIssueCustomFields(issue, issueVo); // 사용자 정의 필드 값 정보 셋팅 this.setRelationIssue(issue, issueVo); //연관 일감 셋팅 this.setDownIssues(issue, issueVo); //하위 일감 세팅 this.setIssueComments(issue, issueVo); // 댓글 정보 셋팅 this.setIssueHistory(issue, issueVo); // 이슈 기록 정보 셋팅 IssueType issueType = this.issueTypeService.getIssueType(issueVo.getIssueTypeVo().getId()); // 이슈의 이슈유형 객체 Integer using = issueType.getUsePartner() != null ? issueType.getUsePartner().intValue() : 0; // 이슈유형별로 사용중인 업체/ISP/호스팅 값 List usePartnerVos = Lists.newArrayList(); for (Integer usePartner : UsePartner.partners) { //1(업체), 2(ISP), 4(호스팅) UsePartnerVo usePartnerVo = UsePartner.checkUsePartner(using, usePartner); if (usePartnerVo != null) { usePartnerVos.add(usePartnerVo); //useCompanyVo.setValues(); } issueVo.setUsePartnerVos(usePartnerVos); } this.setIssueCompanyField(issue, issueVo); //업체 정보 세팅 this.setIssueIspField(issue, issueVo); //ISP 정보 세팅 this.setIssueHostingField(issue, issueVo); //HOSTING 정보 세팅 this.setParentIssue(issue,issueVo); //상위 이슈 정보 세팅 } // 상위일감 정보 추가 private void setParentIssue(Issue issue, IssueVo issueVo) { if(issue.getParentIssue() != null){ issueVo.setParentIssueVo(ConvertUtil.copyProperties(issue.getParentIssue(), IssueVo.class)); } } // 등록자 정보 추가 private void setRegister(List issueVos) { for (IssueVo issueVo : issueVos) { // 사용자 패스워드를 삭제하고 사용자 계정을 복호화한다. issueVo.setRegisterVo(this.userService.removeSensitiveUser(issueVo.getRegisterId())); } } // 이슈 등록자 정보를 셋팅한다. private void setRegister(Issue issue, IssueVo issueVo) { UserVo userVo = this.userService.removeSensitiveUser(issue.getRegisterId()); issueVo.setRegisterVo(userVo); // 등록자는 항상 수정 가능. if (userVo.getId().equals(this.webAppUtil.getLoginId())) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } } // 연관 이슈 정보를 셋팅한다 private void setRelationIssue(Issue issue, IssueVo issueVo) { //Set issueRelations = issue.getIssueRelations(); List> results = this.issueRelationMapper.findByIssueId(issueVo); Long totalCount = this.issueRelationMapper.count(issueVo); if (issue != null && issueVo != null && results.size() > 0) { int totalPage = (int) Math.ceil((totalCount - 1) / issueVo.getRelPageSize()) + 1; issueVo.setRelTotalPage(totalPage); issueVo.setRelTotalCount(totalCount); for (Map result : results) { IssueRelationVo issueRelationVo = ConvertUtil.convertMapToClass(result, IssueRelationVo.class); Issue relationIssue = this.findOne(MapUtil.getLong(result, "relationIssueId")); IssueVo relIssueVo = ConvertUtil.copyProperties(relationIssue, IssueVo.class); Project project = this.projectService.getProject(relationIssue.getProject().getId()); relIssueVo.setProjectId(project.getId()); relIssueVo.setProjectKey(project.getProjectKey()); relIssueVo.setIssueNumber(relationIssue.getIssueNumber()); issueRelationVo.setIssueRelation(relIssueVo); issueRelationVo.setTitle(relationIssue.getTitle()); issueRelationVo.setIssueTypeVo(ConvertUtil.copyProperties(relationIssue.getIssueType(), IssueTypeVo.class)); issueRelationVo.setPriorityVo(ConvertUtil.copyProperties(relationIssue.getPriority(), PriorityVo.class)); issueRelationVo.setSeverityVo(ConvertUtil.copyProperties(relationIssue.getSeverity(), SeverityVo.class)); //이슈 상태 추가 IssueStatusVo issueStatusVo = ConvertUtil.copyProperties(relationIssue.getIssueStatus(), IssueStatusVo.class, "issueStatusType"); issueStatusVo.setIssueStatusType(relationIssue.getIssueStatus().getIssueStatusType().toString()); issueRelationVo.setIssueStatusVo(issueStatusVo); issueRelationVo.setModifyPermissionCheck(issueVo.getModifyPermissionCheck()); this.setRegister(relationIssue, relIssueVo); // 등록자 this.setIssueDepartment(relationIssue, relIssueVo); // 담당부서 정보 셋팅 this.setIssueCustomFields(relationIssue, relIssueVo); // 사용자정의필드 정보 세팅 Set issueCompanies = relationIssue.getIssueCompanies(); Iterator itrCompany = issueCompanies.iterator(); while (itrCompany.hasNext()) { issueRelationVo.addIssueCompanyVo(ConvertUtil.copyProperties(itrCompany.next(), IssueCompanyVo.class)); } Set issueIsps = relationIssue.getIssueIspFields(); Iterator itrIsp = issueIsps.iterator(); while (itrIsp.hasNext()) { issueRelationVo.addIssueIspVo(ConvertUtil.copyProperties(itrIsp.next(), IssueIspVo.class)); } Set issueHostings = relationIssue.getIssueHostingFields(); Iterator itrHosting = issueHostings.iterator(); while (itrHosting.hasNext()) { issueRelationVo.addIssueHostingVo(ConvertUtil.copyProperties(itrHosting.next(), IssueHostingVo.class)); } issueVo.addIssueRelationVo(issueRelationVo); } } else { issue.clearIssueRelations(); } } // 이슈 담당자 정보를 셋팅한다. /*private void setIssueUser(Issue issue, IssueVo issueVo) { List userVos = Lists.newArrayList(); for (IssueUser issueUser : issue.getIssueUsers()) { UserVo userVo = ConvertUtil.copyProperties(issueUser.getUser(), UserVo.class, "password"); userVo.setByName(userVo.getName() + "(" + CommonUtil.decryptAES128(userVo.getAccount()) + ")"); userVo.setAccount(CommonUtil.decryptAES128(userVo.getAccount())); userVos.add(userVo); // 담당자가 있을 경우 담당자만 수정 가능. if (userVo.getId().equals(this.webAppUtil.getLoginId())) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } } // 스케쥴러에서 실행될 경우 오류 발생하므로 권한 체크하지 않는다. if (this.webAppUtil.getLoginId() != null) { // 업무 공간 관리자일 경우 수정 권한을 갖는다. if (this.userWorkspaceService.checkWorkspaceManager()) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } // 프로젝트 관리자일 경우 해당 프로젝트에 등록된 이슈는 수정 권한을 갖는다. if (this.projectRoleUserService.checkProjectManager(issue.getProject())) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } } // 담당자가 없으면 모든 사용자가 수정 가능. if (issue.getIssueUsers().size() < 1) { issueVo.setModifyPermissionCheck(Boolean.TRUE); } issueVo.setUserVos(userVos); }*/ // 이슈 담당부서 정보를 셋팅한다. private void setIssueDepartment(Issue issue, IssueVo issueVo) { List departmentVos = Lists.newArrayList(); for (IssueDepartment issueDepartment : issue.getIssueDepartments()) { DepartmentVo departmentVo = ConvertUtil.copyProperties(issueDepartment.getDepartment(), DepartmentVo.class); departmentVo.setByName(departmentVo.getDepartmentName()); departmentVos.add(departmentVo); List userDepartments = this.userDepartmentRepository.findByDepartmentId(departmentVo.getId()); if (userDepartments != null && userDepartments.size() > 0) { for (UserDepartment userDepartment : userDepartments) { if (userDepartment.getUserId().equals(this.webAppUtil.getLoginId())){ issueVo.setModifyPermissionCheck(Boolean.TRUE); } } } } issueVo.setDepartmentVos(departmentVos); } // 이슈 첨부파일 정보를 셋팅한다. private void setAttachedFiles(Issue issue, IssueVo issueVo) { List attachedFileVos = Lists.newArrayList(); for (AttachedFile attachedFile : issue.getAttachedFiles()) { AttachedFileVo attachedFileVo = ConvertUtil.copyProperties(attachedFile, AttachedFileVo.class, "fileType"); attachedFileVo.setFileType(attachedFile.getFileType().toString()); attachedFileVos.add(attachedFileVo); } issueVo.setAttachedFileVos(attachedFileVos); } // 이슈(이슈 유형)에 연결된 사용자 정의 필드 정보를 셋팅한다. private IssueVo setIssueCustomFields(Issue issue, IssueVo issueVo) { // 해당 프로젝트의 이슈 유형에 연결된 사용자 정의 필드 정보를 가져온다. IssueTypeCustomFieldCondition issueTypeCustomFieldCondition = new IssueTypeCustomFieldCondition(); issueTypeCustomFieldCondition.setProjectId(issue.getProject().getId()); issueTypeCustomFieldCondition.setIssueTypeId(issue.getIssueType().getId()); List issueTypeCustomFieldVos = this.issueTypeCustomFieldService.findIssueTypeCustomField(new HashMap<>(), issueTypeCustomFieldCondition); issueVo.setIssueTypeCustomFieldVos(issueTypeCustomFieldVos); // 이슈에서 사용된 사용자 정의 필드 값을 가져온다. List issueCustomFieldValueVos = this.issueCustomFieldValueService.findByIssueId(issue.getId()); issueVo.setIssueCustomFieldValueVos(issueCustomFieldValueVos); return issueVo; } // 이슈에 등록된 댓글 정보를 셋팅한다. private void setIssueComments(Issue issue, IssueVo issueVo) { issueVo.setIssueCommentVos(this.issueCommentService.findIssueComment(issue.getId())); } // 이슈 기록 정보를 셋팅한다. private void setIssueHistory(Issue issue, IssueVo issueVo) { issueVo.setIssueHistoryVos(this.issueHistoryService.findIssueHistory(issue)); } // 사용자 정의 필드 값이 같은 이슈 찾기 @Override @Transactional public List findIssue(IssueApiForm issueApiform) { List issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues(); List resultIssueVos = Lists.newArrayList(); String comma = ","; List userValues = Lists.newArrayList(); if (issueCustomFieldValueForms.size() > 0) { IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator(); Collections.sort(issueCustomFieldValueForms, comp); String concatUseValue = ""; for (int i = 0; i < issueCustomFieldValueForms.size(); i++) { IssueCustomFieldValueForm issueCustomFieldValueForm = issueCustomFieldValueForms.get(i); userValues.add(issueCustomFieldValueForm.getUseValue()); if (i > 0) { concatUseValue = concatUseValue.concat(comma); } concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue()); } IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition(); issueCustomFieldValueCondition.setUseValue(concatUseValue); issueCustomFieldValueCondition.setUseValues(userValues); issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId()); issueCustomFieldValueCondition.setIssueStatusType("CLOSE"); List> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); if (results != null && results.size() > 0) { for (Map result : results) { resultIssueVos.add(this.getIssue(MapUtil.getLong(result, "id"))); } } } return resultIssueVos; } // 리스트에서 해당 아이디를 가지고 있는 이슈 검색 private IssueVo findIssueVo(List list, Long id) { for (IssueVo issueVo : list) { if (id.equals(issueVo.getId())) { return issueVo; } } return null; } // 이슈를 수정한다(api용) @Override @Transactional public List modifyIssue(IssueApiForm issueApiForm, List files) { User user = this.convertToUser(issueApiForm.getToken()); IssueForm issueForm = this.convertToIssueForm(issueApiForm, user); List issue = this.findIssue(issueApiForm); if (issue != null && issue.size() > 0) { List issues = Lists.newArrayList(); for (Issue issueVo : issue) { issueForm.setId(issueVo.getId()); issueForm.setTitle(issueVo.getTitle()); // 자동 종료 상태 설정이 되어 있지 않으면 오류발생 Issue modifyIssue = this.modifyIssueForApi(user, issueForm, files); Issue parentIssue = modifyIssue.getParentIssue(); IssueType issueType = modifyIssue.getIssueType(); Set issueTypeApiEndStatuses = issueType.getIssueTypeApiEndStatuses(); IssueTypeApiEndStatus issueStatus = null; if (issueTypeApiEndStatuses != null && issueTypeApiEndStatuses.size() > 0) { issueStatus = issueTypeApiEndStatuses.iterator().next(); } else { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_COMPLETE_ISSUE_STATUS_NOT_EXIST)); } if (parentIssue != null) { IssueCondition issueCondition = new IssueCondition(issueVo.getId(), parentIssue.getId()); List> results = this.issueMapper.findNotCompleteByParentIssueId(issueCondition); // 하위 일감이 모두 종료 상태일때 상위 일감도 종료 처리 if (results == null || results.size() == 0) { parentIssue.setIssueStatus(issueStatus.getIssueStatus()); this.issueRepository.saveAndFlush(parentIssue); } } issues.add(modifyIssue); } return issues; } else { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.API_ISSUE_NOT_EXIST)); } } // 이슈를 수정한다. @Override @Transactional public Issue modifyIssue(IssueForm issueForm, List multipartFiles) { User user = this.webAppUtil.getLoginUserObject(); return modifyIssue(user, issueForm, multipartFiles); } // 수정 데이터가 유효한지 확인 private CheckIssueData checkIssue(User user, IssueForm issueForm) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId()); Issue issue = this.getIssue(issueForm.getId()); IssueStatus oldIssueStatus = issue.getIssueStatus(); // 이슈 수정 권한 체크 this.verifyIssueModifyPermission(issue, user); // 프로젝트 유효성 체크 Project project = this.projectService.getProject(issueForm.getProjectId()); // 이슈 상태 유효성 체크 IssueStatus issueStatus = this.issueStatusService.getIssueStatus(issueForm.getIssueStatusId()); // 이슈 유형 유효성 체크 IssueType issueType = this.issueTypeService.getIssueType(issueForm.getIssueTypeId()); // 우선순위 유효성 체크 Priority priority = this.priorityService.getPriority(issueForm.getPriorityId()); // 중요도 유효성 체크 Severity severity = this.severityService.getSeverity(issueForm.getSeverityId()); // 제목 유효성 체크 this.verifyTitle(issueForm.getTitle()); // 날짜 유효성 체크 this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate()); // 담당자 유효성 체크 //this.verifyIssueAssignee(project, issueForm); // 담당부서 유효성 체크 //this.verifyIssueDepartment(project, issueForm); CheckIssueData checkIssueData = new CheckIssueData(); checkIssueData.setIssue(issue); checkIssueData.setProject(project); checkIssueData.setOldIssueStatus(oldIssueStatus); checkIssueData.setNewIssueStatus(issueStatus); checkIssueData.setIssueType(issueType); checkIssueData.setPriority(priority); checkIssueData.setSeverity(severity); return checkIssueData; } // 이슈 수정(API용) private Issue modifyIssueForApi(User user, IssueForm issueForm, List multipartFiles) { CheckIssueData checkIssueData = this.checkIssue(user, issueForm); if (issueForm.getComment() != null && !issueForm.getComment().equals("")) { //댓글 추가 IssueCommentForm issueCommentForm = new IssueCommentForm(); issueCommentForm.setDescription(issueForm.getComment()); issueCommentForm.setIssueId(issueForm.getId()); this.issueCommentService.addIssueComment(issueCommentForm, user); } // 이슈 이력 남기기 this.addIssueHistoryModify(user, issueForm, checkIssueData, multipartFiles); // db에 저장 return this.saveIssue(issueForm, checkIssueData); } private void addIssueHistoryModify(User user, IssueForm issueForm, CheckIssueData checkIssueData, List multipartFiles) { // 변경 이력 정보 추출 StringBuilder detectIssueChange = this.issueHistoryService.detectIssueChange(issueForm, checkIssueData, multipartFiles); // 프로젝트가 변경되면 이슈 넘버를 새로 따야 한다. this.checkChangeProject(checkIssueData.getProject(), checkIssueData.getIssue()); // 이슈 유형이 변경되었는지 확인하고 변경되었다면 이슈 상태 속성이 '대기' 인 이슈 상태로 교체한다. if (this.checkChangeIssueType(checkIssueData.getIssueType(), checkIssueData.getNewIssueStatus(), checkIssueData.getIssue())) { checkIssueData.setNewIssueStatus(this.issueStatusService.findByIssueStatusTypeIsReady(checkIssueData.getIssueType().getWorkflow())); // 이슈 상태 변경 이력 남기기 - 이력을 남기기 위해 issueForm 에 issueStatus Id 값을 저장. issueForm.setIssueStatusId(checkIssueData.getNewIssueStatus().getId()); this.issueHistoryService.detectIssueStatus(checkIssueData.getIssue(), issueForm, detectIssueChange, checkIssueData.getOldIssueStatus(), checkIssueData.getNewIssueStatus()); } // db에 저장 // checkIssueData.setIssue(this.saveIssue(issueForm, checkIssueData)); // 이슈 이력 등록 if (!StringUtils.isEmpty(detectIssueChange.toString())) { this.issueHistoryService.addIssueHistory(checkIssueData.getIssue(), user, IssueHistoryType.MODIFY, detectIssueChange.toString()); } // 사용자 시스템 기능 사용 정보 수집 UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class); log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_MODIFY)); } private Issue saveIssue(IssueForm issueForm, CheckIssueData checkIssueData) { Issue issue = checkIssueData.getIssue(); ConvertUtil.copyProperties(issueForm, issue, "id"); issue.setProject(checkIssueData.getProject()); issue.setIssueStatus(checkIssueData.getNewIssueStatus()); issue.setIssueType(checkIssueData.getIssueType()); issue.setPriority(checkIssueData.getPriority()); issue.setSeverity(checkIssueData.getSeverity()); issue.setStartDate(issueForm.getStartDate()); issue.setCompleteDate(issueForm.getCompleteDate()); return this.issueRepository.saveAndFlush(issue); } // 이슈를 수정한다. @Override @Transactional public Issue modifyIssue(User user, IssueForm issueForm, List multipartFiles) { CheckIssueData checkIssueData = this.checkIssue(user, issueForm); Issue issue = checkIssueData.getIssue(); IssueStatus oldIssueStatus = checkIssueData.getOldIssueStatus(); Project project = checkIssueData.getProject(); IssueStatus issueStatus = checkIssueData.getNewIssueStatus(); IssueType issueType = checkIssueData.getIssueType(); // 변경 이력 정보 추출 StringBuilder detectIssueChange = this.issueHistoryService.detectIssueChange(issueForm, checkIssueData, multipartFiles); // 프로젝트가 변경되면 이슈 넘버를 새로 따야 한다. this.checkChangeProject(project, issue); // 이슈 유형이 변경되었는지 확인하고 변경되었다면 이슈 상태 속성이 '대기' 인 이슈 상태로 교체한다. if (this.checkChangeIssueType(issueType, issueStatus, issue)) { issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow()); // 이슈 상태 변경 이력 남기기 - 이력을 남기기 위해 issueForm 에 issueStatus Id 값을 저장. issueForm.setIssueStatusId(issueStatus.getId()); this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, oldIssueStatus, issueStatus); } issue = this.saveIssue(issueForm, checkIssueData); //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds()); // 담당부서 지정 if(issueForm.getDepartmentIds().size()>0){ this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds()); } // multipartFile 을 file Map List 객체로 변경한다. List> convertFileMaps = this.convertMultipartFileToFile(multipartFiles); // 첨부 파일 저장 - 비동기로 작동 this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount()); // 삭제된 첨부파일 처리 this.attachedFileService.removeAttachedFiles(issueForm.getRemoveFiles()); // 텍스트 에디터에 첨부한 파일을 이슈와 연결 this.checkNotHaveIssueIdAttachedFile(issue, issueForm); // 사용자 정의 필드 저장 this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields()); // 사용자 시스템 기능 사용 정보 수집 UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class); log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_MODIFY)); // 업체 정보 저장 this.issueCompanyService.modifyIssueCompanyField(issue, issueForm, detectIssueChange); // ISP 정보 저장 this.issueIspService.modifyIssueIspField(issue, issueForm, detectIssueChange); // HOSTING 정보 저장 this.issueHostingService.modifyIssueHostingField(issue, issueForm, detectIssueChange); // 이슈 이력 등록 if (!StringUtils.isEmpty(detectIssueChange.toString())) { this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString()); } return issue; } // multipartFile 을 file Map 객체로 변경한다. private List> convertMultipartFileToFile(List multipartFiles) { List> convertFileMaps = Lists.newArrayList(); if (multipartFiles != null && multipartFiles.size() > 0) { for (MultipartFile multipartFile : multipartFiles) { try { Map fileMap = CommonUtil.makeFileMap(multipartFile); convertFileMaps.add(fileMap); } catch (Exception e) { log.debug("multipartFile -> file 변환 오류" + e.getMessage()); } } } return convertFileMaps; } // 프로젝트가 변경되었는지 확인한다. private void checkChangeProject(Project newProject, Issue issue) { if (!issue.getProject().getId().equals(newProject.getId())) { // 각 프로젝트의 고유 이슈 번호 생성 issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(newProject)); } } // 이슈 유형이 변경되었는지 확인하고 변경되었으면 이슈 상태를 대기 속성인 이슈 상태로 셋팅한다. private Boolean checkChangeIssueType(IssueType newIssueType, IssueStatus issueStatus, Issue issue) { if (!issue.getIssueType().getId().equals(newIssueType.getId())) { // 이슈 상태를 선택하지 않았을 때 if (issueStatus == null) { return true; } // 이슈 상태의 속성이 '대기' 가 아닌 경우 if (!issueStatus.getIssueStatusType().equals(IssueStatusType.READY)) { return true; } else { // 변경하는 이슈 유형의 워크플로우에 존재하는 상태 속성 '대기'와 동일한 상태인지 확인 IssueStatus newReadyIssueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(newIssueType.getWorkflow()); if (!newReadyIssueStatus.getId().equals(issueStatus.getId())) { return true; } } } return false; } // 이슈 담당부서로 지정될 부서가 해당 프로젝트에 참여 하고 있는 부서인지 확인 private void verifyIssueDepartment(Project project, IssueForm issueForm) { if (issueForm.getDepartmentIds().size() > 0) { List trustDepartmentIds = Lists.newArrayList(); // 참여 확인된 부서 for (Long departmentId : issueForm.getDepartmentIds()) { boolean includeProject = false; for (ProjectRole projectRole : project.getProjectRoles()) { ProjectRoleDepartment projectRoleDepartment = this.projectRoleDepartmentService.findByProjectRoleIdAndDepartmentId(projectRole.getId(), departmentId); if (projectRoleDepartment != null) { includeProject = true; trustDepartmentIds.add(departmentId); break; } } // 데이터 보정 작업 - 프로젝트에서 제외된 사용자는 담당자에서 제외 될 수 있도록 처리 if (!includeProject) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.PROJECT_NOT_INCLUDE_DEPARTMENT)); } } // 참여 확인된 부서로 담당부서 변경 issueForm.setDepartmentIds(trustDepartmentIds); } } // 이슈 담당자로 지정될 사용자가 해당 프로젝트에 참여 하고 있는 사용자 인지 확인 private void verifyIssueAssignee(Project project, IssueForm issueForm) { if (issueForm.getUserIds().size() > 0) { List trustUserIds = Lists.newArrayList(); // 참여 확인된 사용자 for (Long userId : issueForm.getUserIds()) { boolean includeProject = false; for (ProjectRole projectRole : project.getProjectRoles()) { ProjectRoleUser projectRoleUser = this.projectRoleUserService.findByProjectRoleIdAndUserId(projectRole.getId(), userId); if (projectRoleUser != null) { includeProject = true; trustUserIds.add(userId); break; } } // 데이터 보정 작업 - 프로젝트에서 제외된 사용자는 담당자에서 제외 될 수 있도록 처리 if (!includeProject) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.PROJECT_NOT_INCLUDE_USER)); } } // 참여 확인된 사용자로 담당자 변경 issueForm.setUserIds(trustUserIds); } } // 이슈 수정 권한 체크 private void verifyIssueModifyPermission(Issue issue, User user) { // 이슈 수정 권한을 갖고 있는지 확인 if (!this.checkHasPermission(ConvertUtil.copyProperties(issue, IssueVo.class), this.getIssueUserVos(issue), user, this.getIssueDepartmentVos(issue))) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_MODIFY_PERMISSION)); } } // 이슈에서 담당자 정보를 추출한다. private List getIssueUserVos(Issue issue) { List userVos = Lists.newArrayList(); Set issueUsers = issue.getIssueUsers(); try { for (IssueUser issueUser : issueUsers) { User user = issueUser.getUser(); UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class, "password"); userVos.add(userVo); } } catch (Exception ex) { } return userVos; } // 이슈에서 담당자 정보를 추출한다. private List getIssueDepartmentVos(Issue issue) { List departmentVos = Lists.newArrayList(); Set issueDepartments = issue.getIssueDepartments(); try { for (IssueDepartment issueDepartment : issueDepartments) { Department department = issueDepartment.getDepartment(); DepartmentVo departmentVo = ConvertUtil.copyProperties(department, DepartmentVo.class); departmentVos.add(departmentVo); } } catch (Exception ex) { } return departmentVos; } // 이슈 수정 권한을 갖고 있는지 확인 private boolean checkHasPermission(IssueVo issueVo, List issueUserVos, User user, List departmentVos) { boolean hasPermission = false; // 업무 공간 관리자일 경우 수정 권한을 갖는다. hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.WORKSPACE_MANAGER, issueVo, null, null, user); // 프로젝트 관리자일 경우 해당 프로젝트에 등록된 이슈는 수정 권한을 갖는다. hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.PROJECT_MANAGER, issueVo, null, null, user); // 이슈 관리자일 경우 수정 권한을 갖는다. hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ISSUE_MANAGER, issueVo, null, null, user); // 이슈 등록자일 경우 수정 권한을 갖는다. hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.REGISTER, issueVo, null, null, user); // 이슈 담당자일 경우 수정 권한을 갖는다. //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ASSIGNEE, issueVo, issueUserVos); // 이슈 담당부서일 경우 수정 권한을 갖는다. hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.DEPARTMENT, issueVo, null, departmentVos, user); // 담당자가 없으면 모든 사용자가 수정 권한을 갖는다. //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ALL_ISSUE_MANAGER, issueVo, null, null, user); //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ALL_PROJECT_MANAGER, issueVo, null, null, user); return hasPermission; } // 이슈 수정 권한을 확인한다. private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List issueUserVos, List departmentVos, User user) { if (!hasPermission) { switch (checkType) { case Issue.WORKSPACE_MANAGER: // 업무 공간 관리자 // 업무 공간 관리자일 경우 수정 권한을 갖는다. hasPermission = this.userWorkspaceService.checkWorkspaceManager(user); break; case Issue.PROJECT_MANAGER: // 프로젝트 관리자 Issue issue = this.getIssue(issueVo.getId()); // 프로젝트 관리자일 경우 해당 프로젝트에 등록된 이슈는 수정 권한을 갖는다. hasPermission = this.projectRoleUserService.checkProjectManager(issue.getProject(), user); break; case Issue.ISSUE_MANAGER: // 이슈 관리자 UserLevel userLevel = this.userLevelService.getUserLevel(user.getUserLevel().getId()); hasPermission = MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE); break; case Issue.REGISTER: // 이슈 등록자 hasPermission = issueVo.getRegisterId().equals(user.getId()); break; case Issue.ASSIGNEE: // 담당자가 없으면 모든 사용자가 수정 권한을 갖는다. if (issueUserVos.size() < 1) { hasPermission = true; break; } // 이슈 담당자 여부 확인 for (UserVo issueUserVo : issueUserVos) { if (issueUserVo.getId().equals(user.getId())) { hasPermission = true; break; } } break; case Issue.DEPARTMENT: // 담당부서가 없으면 모든 사용자가 수정 권한을 갖는다. /*if (userDepartmentVos.size() < 1) { hasPermission = true; break; }*/ // 이슈 담당부서 여부 확인 for (DepartmentVo departmentVo : departmentVos) { List userDepartments = this.userDepartmentService.findByDepartmentId(departmentVo.getId()); if(userDepartments != null && userDepartments.size() > 0) { for (UserDepartment userDepartment : userDepartments) { if (userDepartment.getUserId().equals(user.getId())){ hasPermission = true; break; } } } } break; } } return hasPermission; } // 이슈 상태 변경 @Override @Transactional public void modifyIssueStatus(IssueForm issueForm, User user) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(); // 변경 이력 정보 추출 StringBuilder detectIssueChange = new StringBuilder(); // 이슈 수정 권한 체크 Issue issue = this.getIssue(issueForm.getId()); IssueStatus oldIssueStatus = issue.getIssueStatus(); this.verifyIssueModifyPermission(issue, user); IssueStatus issueStatus = this.issueStatusService.getIssueStatus(issueForm.getIssueStatusId()); if (issueStatus.getIssueStatusType().toString().equals("CLOSE")) { List downIssuesStatus = issueForm.getDownIssuesStatus(); if (downIssuesStatus != null && downIssuesStatus.size() > 0) { for (String downIssueStatus : downIssuesStatus) { if (!downIssueStatus.equals("CLOSE")) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_MODIFY_STATUS)); } } } } // 이슈 상태를 변경할 때 선택한 이슈 상태로 변경할 수 있는지 확인한다. this.issueStatusService.checkNextIssueStatus(issue, issueStatus); // 변경 이력 정보 추출 this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, oldIssueStatus, issueStatus); issue.setIssueStatus(issueStatus); this.issueRepository.saveAndFlush(issue); // 코멘트 등록 if (!StringUtils.isEmpty(issueForm.getComment())) { IssueCommentForm issueCommentForm = new IssueCommentForm(); issueCommentForm.setIssueId(issue.getId()); issueCommentForm.setDescription(issueForm.getComment()); this.issueCommentService.addIssueComment(issueCommentForm); } // 이슈 이력 등록 if (!StringUtils.isEmpty(detectIssueChange.toString())) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("
    "); stringBuilder.append(detectIssueChange.toString()); stringBuilder.append("
"); this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, stringBuilder.toString()); } // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_STATUS_CHANGE)); } // 이슈 담당자 변경 @Override @Transactional public void modifyIssueUser(IssueForm issueForm) { User user = this.webAppUtil.getLoginUserObject(); // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(); // 변경 이력 정보 추출 StringBuilder detectIssueChange = new StringBuilder(); // 이슈 수정 권한 체크 Issue issue = this.getIssue(issueForm.getId()); this.verifyIssueModifyPermission(issue, user); issue.setProject(this.projectService.getProject(issueForm.getProjectId())); // 변경 이력 정보 추출 this.issueHistoryService.detectIssueManager(issue, issueForm, detectIssueChange); this.issueUserService.modifyIssueUser(issue, issue.getProject().getWorkspace(), issueForm.getDepartmentIds()); //getUserIds -> getDepartmentIds this.issueRepository.saveAndFlush(issue); // 이슈 이력 등록 if (!StringUtils.isEmpty(detectIssueChange.toString())) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("
    "); stringBuilder.append(detectIssueChange.toString()); stringBuilder.append("
"); this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, stringBuilder.toString()); } // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_USER_CHANGE)); } @Override @Transactional public void modifyIssueDepartment(IssueForm issueForm) { User user = this.webAppUtil.getLoginUserObject(); // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(); // 변경 이력 정보 추출 StringBuilder detectIssueChange = new StringBuilder(); // 이슈 수정 권한 체크 Issue issue = this.getIssue(issueForm.getId()); this.verifyIssueModifyPermission(issue, user); issue.setProject(this.projectService.getProject(issueForm.getProjectId())); // 변경 이력 정보 추출 this.issueHistoryService.detectIssueDepartment(issue, issueForm, detectIssueChange); //this.issueUserService.modifyIssueUser(issue, issue.getProject().getWorkspace(), issueForm.getUserIds()); this.issueDepartmentService.modifyIssueDepartment(issue, issue.getProject().getWorkspace(), issueForm.getDepartmentIds()); this.issueRepository.saveAndFlush(issue); // 이슈 이력 등록 if (!StringUtils.isEmpty(detectIssueChange.toString())) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("
    "); stringBuilder.append(detectIssueChange.toString()); stringBuilder.append("
"); this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, stringBuilder.toString()); } // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_USER_CHANGE)); } // 이슈를 삭제한다. @Override @Transactional public void removeIssues(IssueForm issueForm) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. User user = this.webAppUtil.getLoginUserObject(); this.workspaceService.checkUseWorkspace(); if (issueForm.getRemoveIds().size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_REMOVE_NOT_SELECT)); } List removeIssues = Lists.newArrayList(); for (Long issueId : issueForm.getRemoveIds()) { //하위이슈 체크 List downIssues = this.issueRepository.findByParentIssueId(issueId); if(downIssues != null && downIssues.size() > 0){ for(Issue downIssue : downIssues){ if(downIssue.getParentIssue() != null){ downIssue.setParentIssue(null); } } } Issue issue = this.issueRemoves(issueId, user); removeIssues.add(issue); } /*if (removeIssues.size() > 0) { this.issueRepository.deleteAll(removeIssues); }*/ // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_REMOVE)); } // 이슈를 삭제한다. @Override @Transactional public void removeAllIssues(IssueForm issueForm) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. User user = this.webAppUtil.getLoginUserObject(); this.workspaceService.checkUseWorkspace(); if (issueForm.getRemoveIds().size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_REMOVE_NOT_SELECT)); } List removeIssues = Lists.newArrayList(); for (Long issueId : issueForm.getRemoveIds()) { //하위이슈 체크 List downIssues = this.issueRepository.findByParentIssueId(issueId); if(downIssues != null && downIssues.size() > 0){ for(Issue downIssue : downIssues){ Long downIssueId = downIssue.getId(); downIssue = this.issueRemoves(downIssueId, user); removeIssues.add(downIssue); } } Issue issue = this.issueRemoves(issueId, user); removeIssues.add(issue); } // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_REMOVE)); } // 하위이슈를 삭제한다. @Override @Transactional public void removeDownIssues(IssueForm issueForm) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. User user = this.webAppUtil.getLoginUserObject(); this.workspaceService.checkUseWorkspace(); if (issueForm.getRemoveIds().size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_REMOVE_NOT_SELECT)); } List removeIssues = Lists.newArrayList(); Long downIssueId = 0L; for (Long issueId : issueForm.getRemoveIds()) { //삭제 할 이슈의 하위이슈 체크 List downIssues = this.issueRepository.findByParentIssueId(issueId); if(downIssues != null && downIssues.size() > 0){ for(Issue downIssue : downIssues){ downIssueId = downIssue.getId(); } } Issue issue = this.issueRemoves(downIssueId, user); removeIssues.add(issue); } // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_REMOVE)); } private Issue issueRemoves(Long issueId, User user) { Issue issue = null; if(issueId != null){ issue = this.getIssue(issueId); } // 이슈 수정 권한을 갖고 있는지 확인 this.verifyIssueModifyPermission(issue, user); // 이슈 첨부 파일을 삭제한다. if (issue.getAttachedFiles().size() > 0) { List attachedFileIds = Lists.newArrayList(); for (AttachedFile attachedFile : issue.getAttachedFiles()) { attachedFileIds.add(attachedFile.getId()); } // 첨부파일 삭제 this.attachedFileService.removeAttachedFiles(attachedFileIds); } // 지울 이슈가 연관이슈인지 체크 후 연관이슈 테이블에서도 삭제한다. List issueRelationList = this.issueRelationRepository.findByRelationIssueId(issueId); if (issueRelationList != null && issueRelationList.size() > 0) { for(IssueRelation issueRelation : issueRelationList){ StringBuilder sb = new StringBuilder(); issueHistoryService.detectRelationIssue(IssueHistoryType.DELETE, issueRelation, sb); issueHistoryService.addIssueHistory(issueRelation.getIssue(), IssueHistoryType.MODIFY, sb.toString()); this.issueRelationRepository.delete(issueRelation); } } // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. this.reservationIssueEmail(issue, EmailType.ISSUE_REMOVE); // 이슈 삭제 this.issueRepository.delete(issue); return issue; } @Override @Transactional(readOnly = true) public Issue getIssue(Long id) { if (id == null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST)); } Issue issue = this.findOne(id); if (issue == null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST)); } return issue; } // 이슈 유형을 사용하는 이슈 갯수를 조회한다. @Override @Transactional(readOnly = true) public long countByIssueTypeId(Long issueTypeId) { return this.issueMapper.countByIssueTypeId(issueTypeId); } // 이슈 상태를 사용하는 이슈 갯수를 조회한다. @Override @Transactional(readOnly = true) public long countByIssueStatus(Long issueStatusId) { return this.issueMapper.countByIssueStatusId(issueStatusId); } // 이슈 유형에서 워크플로우가 변경되었을 때 해당 워크플로우에 현재 이슈 상태가 존재하지 않으면 대기(생성) 로 변경한다. @Override @Transactional public void changeWorkflows(Workflow workflow, IssueType issueType) { List> issueMaps = this.issueMapper.findByIssueTypeId(issueType.getId()); List issueStatusVos = this.issueStatusService.findByWorkflowId(workflow.getId()); IssueStatus readyIssueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(workflow); List updateIssues = Lists.newArrayList(); for (Map issueMap : issueMaps) { boolean exist = false; for (IssueStatusVo issueStatusVo : issueStatusVos) { Long issueStatusId = MapUtil.getLong(issueMap, "issueStatusId"); if (issueStatusId == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_STATUS_NOT_EXIST)); } if (issueStatusId.equals(issueStatusVo.getId())) { exist = true; break; } } // 존재하지 않는 대상은 if (!exist) { StringBuilder stringBuilder = new StringBuilder(); String issueStatusName = MapUtil.getString(issueMap, "issueStatusName"); if (issueStatusName == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_STATUS_NOT_EXIST)); } Issue issue = this.getIssue(MapUtil.getLong(issueMap, "issueId")); // 워크플로우에서 이슈 상태가 삭제되어 상태가 변경된 정보를 기록한다. this.issueHistoryService.recordRemoveWorkflowToIssueStatus(issueStatusName, readyIssueStatus.getName(), stringBuilder); this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, stringBuilder.toString()); issue.setIssueStatus(readyIssueStatus); updateIssues.add(issue); } } if (updateIssues.size() > 0) { this.issueRepository.saveAll(updateIssues); for (Issue issue : updateIssues) { // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue); } } } // 이슈 목록을 엑셀로 다운로드 한다. @Override @Transactional public ModelAndView downloadExcel(HttpServletRequest request, Model model) { // 사용 공간에서 로그인한 사용자가 비활성인지 확인하고 비활성일 경우 엑셀 다운로드를 금지한다. ModelAndView modelAndView = this.workspaceService.checkUseExcelDownload(model); if (modelAndView != null) { return modelAndView; } Map conditions = new HashMap<>(); // 엑셀 다운로드에 필요한 검색 조건 정보를 추출하고 검색 조건 추출에 오류가 발생하면 경고를 표시해준다. modelAndView = this.excelConditionCheck.checkCondition(conditions, request, model); if (modelAndView != null) { return modelAndView; } IssueCondition issueCondition = IssueCondition.make(conditions); // 검색 조건을 만든다 this.makeIssueSearchCondition(issueCondition, Lists.newArrayList("01", "02", "03"), null); Set issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션 Map resJsonData = new HashMap<>(); ExportExcelVo excelInfo = new ExportExcelVo(); excelInfo.setFileName(this.messageAccessor.message("common.issueList")); // 이슈 목록 excelInfo.addAttrInfos(new ExportExcelAttrVo("issueStatusName", this.messageAccessor.message("common.status"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // 상태 excelInfo.addAttrInfos(new ExportExcelAttrVo("issueKey", this.messageAccessor.message("common.issueKey"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // 이슈 번호 excelInfo.addAttrInfos(new ExportExcelAttrVo("title", this.messageAccessor.message("common.issueTitle"), 40, ExportExcelAttrVo.ALIGN_LEFT)); // 이슈 제목 excelInfo.addAttrInfos(new ExportExcelAttrVo("description", this.messageAccessor.message("common.content"), 60, ExportExcelAttrVo.ALIGN_LEFT)); // 내용 excelInfo.addAttrInfos(new ExportExcelAttrVo("issueTypeName", this.messageAccessor.message("common.issueType"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // 이슈 타입 excelInfo.addAttrInfos(new ExportExcelAttrVo("departments", this.messageAccessor.message("common.department"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 담당부서 excelInfo.addAttrInfos(new ExportExcelAttrVo("priorityName", this.messageAccessor.message("common.priority"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // 우선순위 excelInfo.addAttrInfos(new ExportExcelAttrVo("severityName", this.messageAccessor.message("common.importance"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // 중요도 excelInfo.addAttrInfos(new ExportExcelAttrVo("register", this.messageAccessor.message("common.register"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 등록자 excelInfo.addAttrInfos(new ExportExcelAttrVo("period", this.messageAccessor.message("common.period"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 기간 excelInfo.addAttrInfos(new ExportExcelAttrVo("modifyDate", this.messageAccessor.message("common.modifyDate"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 최종 변경일 excelInfo.addAttrInfos(new ExportExcelAttrVo("companyName", this.messageAccessor.message("common.company"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 업체 excelInfo.addAttrInfos(new ExportExcelAttrVo("ispName", this.messageAccessor.message("common.isp"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // ISP excelInfo.addAttrInfos(new ExportExcelAttrVo("hostingName", this.messageAccessor.message("common.hosting"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 호스팅 // 사용자 정의 필드를 사용한 이슈를 찾는다. 만약 이슈가 없다면 여기서 이슈 조회가 끝난다. if (!this.searchUseCustomFields(issueCondition, issueIds, resJsonData, null)) { model.addAttribute(Constants.EXCEL, excelInfo); return new ModelAndView(this.excelView); } List issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션 // 사용자 정의 필드로 검색한 이슈 아이디 값 List issueKeys = Lists.newArrayList(issueIds); issueCondition.setIssueIds(issueKeys); List> results = this.issueMapper.find(issueCondition); // 엑셀 다운로드를 진행할 때 전체 사용자 정의 필드를 표시한다. this.makeIssueExcelDownloadCustomFields(excelInfo); // 이슈 아이디 초기화 issueCondition.setIssueIds(Lists.newArrayList()); // Map 에 있는 데이터를 IssueVo 데이터로 변환한다. User user = this.webAppUtil.getLoginUserObject(); this.setMapToIssueVo(results, issueVos, issueCondition, user); // IssueVos 데이터를 엑셀에서 표시할 수 있는 데이터로 변경한다. List> convertExcelViewToIssueMaps = this.convertExcelViewToIssueVos(issueVos); if (results.size() > EXCEL_DOWNLOAD_MAX_ROWS) { // 엑셀 1만건 초과 알림 this.simpMessagingTemplate.convertAndSendToUser(this.webAppUtil.getLoginUser().getAccount(), "/notification/system-alert", this.messageAccessor.getMessage(MsgConstants.EXCEL_DOWNLOAD_MAX_ROWS_OVER)); // 1만 건만 출력해준다. excelInfo.setDatas(convertExcelViewToIssueMaps.subList(0, EXCEL_DOWNLOAD_MAX_ROWS)); model.addAttribute(Constants.EXCEL, excelInfo); return new ModelAndView(this.excelView); } // 엑셀에 넣을 데이터 - IssueVos 데이터를 엑셀에서 표시할 수 있는 데이터로 변경한다. excelInfo.setDatas(convertExcelViewToIssueMaps); model.addAttribute(Constants.EXCEL, excelInfo); return new ModelAndView(this.excelView); } // 엑셀 다운로드를 진행할 때 전체 사용자 정의 필드를 표시한다. private void makeIssueExcelDownloadCustomFields(ExportExcelVo excelInfo) { List customFields = this.customFieldService.findByWorkspaceId(); for (CustomField customField : customFields) { excelInfo.addAttrInfos(new ExportExcelAttrVo("customField_" + customField.getId(), customField.getName(), 10, ExportExcelAttrVo.ALIGN_CENTER)); } } // 사용자 정의 필드 정보 추가 private void setIssueCustomFieldValue(List issueVos, IssueCondition issueCondition) { // 이슈에서 저장한 사용자 정의 필드 값을 조회한다. List> issueCustomFieldValues = this.issueCustomFieldValueService.findInIssueIds(issueCondition); for (IssueVo issueVo : issueVos) { for (Map issueCustomFieldValue : issueCustomFieldValues) { if (issueVo.getId().equals(MapUtil.getLong(issueCustomFieldValue, "issueId"))) { IssueCustomFieldValueVo issueCustomFieldValueVo = new IssueCustomFieldValueVo(); issueCustomFieldValueVo.setUseValue(MapUtil.getString(issueCustomFieldValue, "useValue")); CustomFieldVo customFieldVo = new CustomFieldVo(); customFieldVo.setId(MapUtil.getLong(issueCustomFieldValue, "customFieldId")); issueCustomFieldValueVo.setCustomFieldVo(customFieldVo); issueVo.addIssueCustomFieldValueVo(issueCustomFieldValueVo); } } } } // 업체 정보 추가 private void setIssueCompanyField(Issue issue, IssueVo issueVo) { List issueCompanyVos = Lists.newArrayList(); for(IssueCompany issueCompany : issue.getIssueCompanies()){ IssueCompanyVo issueCompanyVo = ConvertUtil.copyProperties(issueCompany, IssueCompanyVo.class); issueCompanyVo.setId(issueCompany.getId()); CompanyField companyField = issueCompany.getCompanyField(); if (companyField != null) { issueCompanyVo.setCompanyId(issueCompany.getCompanyField().getId()); if (issueCompany.getCompanyTypeId() != null && issueCompany.getCompanyTypeId() != -1) { CompanyFieldCategory companyType = this.companyFieldCategoryService.find(issueCompany.getCompanyTypeId()); issueCompanyVo.setCompanyTypeName(companyType.getUseValue()); } if (issueCompany.getParentSectorId() != null && issueCompany.getParentSectorId() != -1) { CompanyFieldCategory parentSector = this.companyFieldCategoryService.find(issueCompany.getParentSectorId()); issueCompanyVo.setParentSectorName(parentSector.getUseValue()); } if (issueCompany.getChildSectorId() != null && issueCompany.getChildSectorId() != -1) { CompanyFieldCategory childSector = this.companyFieldCategoryService.find(issueCompany.getChildSectorId()); issueCompanyVo.setChildSectorName(childSector.getUseValue()); } if (issueCompany.getRegionId() != null && issueCompany.getRegionId() != -1) { CompanyFieldCategory region = this.companyFieldCategoryService.find(issueCompany.getRegionId()); issueCompanyVo.setRegionName(region.getUseValue()); } if (issueCompany.getStatusId() != null && issueCompany.getStatusId() != -1) { if (issueCompany.getStatusName() != null && !issueCompany.getStatusName().equals("")) { issueCompanyVo.setStatusName(issueCompany.getStatusName()); } else { CompanyFieldCategory status = this.companyFieldCategoryService.find(issueCompany.getStatusId()); issueCompanyVo.setStatusName(status.getUseValue()); } } } issueCompanyVos.add(issueCompanyVo); } issueVo.setIssueCompanyVos(issueCompanyVos); } // Isp 정보 추가 private void setIssueIspField(Issue issue, IssueVo issueVo) { List issueIspVos = Lists.newArrayList(); for(IssueIsp issueIsp : issue.getIssueIspFields()){ IssueIspVo issueIspVo = ConvertUtil.copyProperties(issueIsp, IssueIspVo.class); issueIspVo.setId(issueIsp.getId()); IspField ispField = issueIsp.getIspField(); if (ispField != null) { issueIspVo.setIspId(ispField.getId()); } issueIspVos.add(issueIspVo); } issueVo.setIssueIspVos(issueIspVos); } // Hosting 정보 추가 private void setIssueHostingField(Issue issue, IssueVo issueVo) { List issueHostingVos = Lists.newArrayList(); for(IssueHosting issueHosting : issue.getIssueHostingFields()){ IssueHostingVo issueHostingVo = ConvertUtil.copyProperties(issueHosting, IssueHostingVo.class); issueHostingVo.setId(issueHosting.getId()); HostingField hostingField = issueHosting.getHostingField(); if (hostingField != null) { issueHostingVo.setHostingId(hostingField.getId()); } issueHostingVos.add(issueHostingVo); } issueVo.setIssueHostingVos(issueHostingVos); } // 연관일감 정보 추가 private void setRelationIssue(IssueVo issueVo, Long issueId) { List relationIssues = this.issueRelationService.findRelationIssue(issueId); issueVo.setIssueRelationIssueVos(relationIssues); } // IssueVos 데이터를 엑셀에서 표시할 수 있는 데이터로 변경한다. private List> convertExcelViewToIssueVos(List issueVos) { List> results = Lists.newArrayList(); for (IssueVo issueVo : issueVos) { try { Map result = new HashMap<>(); result.put("issueStatusName", issueVo.getIssueStatusName()); result.put("issueKey", issueVo.getProjectKey() + "-" + issueVo.getIssueNumber()); result.put("title", issueVo.getTitle()); String description = ""; if (issueVo.getDescription() != null) { description = Jsoup.parse(issueVo.getDescription()).text(); // HTML 태그 제거 description = description.replaceAll("\\<.*?>", ""); // 공백 제거 } result.put("description", description); result.put("issueTypeName", issueVo.getIssueTypeName()); result.put("assignees", CommonUtil.convertUserVosToString(issueVo.getUserVos())); result.put("departments", CommonUtil.convertDepartmentVosToString(issueVo.getDepartmentVos())); result.put("priorityName", issueVo.getPriorityName()); result.put("severityName", issueVo.getSeverityName()); result.put("companyName", issueVo.getCompanyName()); result.put("ispName", issueVo.getIspName()); result.put("hostingName", issueVo.getHostingName()); UserVo register = this.userService.removeSensitiveUser(issueVo.getRegisterId()); // 등록자 result.put("register", register.getByName()); // 최종 변경일 result.put("modifyDate", issueVo.getModifyDate()); if (StringUtils.isEmpty(issueVo.getStartDate())) { result.put("period", ""); } else { result.put("period", issueVo.getStartDate() + " ~ " + issueVo.getCompleteDate()); } for (IssueCustomFieldValueVo issueCustomFieldValueVo : issueVo.getIssueCustomFieldValueVos()) { // 사용자 정의 필드 값 저장이 아직 안되어 있는 경우 if (result.get("customField_" + issueCustomFieldValueVo.getCustomFieldVo().getId()) == null) { result.put("customField_" + issueCustomFieldValueVo.getCustomFieldVo().getId().toString(), issueCustomFieldValueVo.getUseValue()); } else { // 이미 저장되어 있으면 다중 선택 사용자 정의 필드 값이다. String useValue = result.get("customField_" + issueCustomFieldValueVo.getCustomFieldVo().getId()); result.put("customField_" + issueCustomFieldValueVo.getCustomFieldVo().getId().toString(), useValue + ", " + issueCustomFieldValueVo.getUseValue()); } } results.add(result); } catch (Exception e) { log.error("엑셀 다운로드 오류 발생"); } } return results; } // 이슈 다중 상태 변경 @Override @Transactional public void modifyMultiIssueStatus(IssueForm issueForm) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(); User user = this.webAppUtil.getLoginUserObject(); for (Long issueId : issueForm.getIds()) { issueForm.setId(issueId); // 이슈 상태 변경 this.modifyIssueStatus(issueForm, user); } // 담당 부서 수정 if (issueForm.getDepartmentIds().size() > 0) { Issue issue = this.getIssue(issueForm.getId()); Project project = this.projectService.getProject(issueForm.getProjectId()); this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds()); } } // 이슈 Import 용 엑셀 템플릿 다운로드 @Override @Transactional public ModelAndView downloadExcelTemplate(HttpServletRequest request, Model model) { Map conditions; try { // 엑셀 다운로드에 필요한 검색 조건 정보를 추출한다. conditions = CommonUtil.getSearchConditions(request); } catch (IOException e) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EXCEL_CONDITIONS_NOT_EXIST)); } ExportExcelVo excelInfo = new ExportExcelVo(); excelInfo.setHideCount(true); excelInfo.setFileName(this.messageAccessor.message("common.registerExcelIssue")); // 엑셀로 이슈 등록하기 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.title"), 20, ExportExcelAttrVo.ALIGN_CENTER)); // 제목 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.content"), 40, ExportExcelAttrVo.ALIGN_CENTER)); // 내용 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.priority"), 5, ExportExcelAttrVo.ALIGN_CENTER)); // 우선순위 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.importance"), 5, ExportExcelAttrVo.ALIGN_CENTER)); // 중요도 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.startDate"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // 시작일 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.endDate"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // 종료일 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.company"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // 업체 excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.isp"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // ISP excelInfo.addAttrInfos(new ExportExcelAttrVo("id", this.messageAccessor.message("common.hosting"), 10, ExportExcelAttrVo.ALIGN_CENTER)); // 호스팅 // 프로젝트에 연결된 사용자 정의 필드 정보를 추출하여 엑셀 download 템플릿을 만든다. this.makeIssueExcelTemplateCustomFields(excelInfo, conditions); // 엑셀에 넣을 데이터 - IssueVos 데이터를 엑셀에서 표시할 수 있는 데이터로 변경한다. excelInfo.setDatas(Lists.newArrayList(new IssueVo())); model.addAttribute(Constants.EXCEL, excelInfo); return new ModelAndView(this.excelView); } // 프로젝트에 연결된 사용자 정의 필드 정보를 추출하여 엑셀 download 템플릿을 만든다. private void makeIssueExcelTemplateCustomFields(ExportExcelVo excelInfo, Map conditions) { List issueTypeCustomFields = this.issueTypeCustomFieldService.findByProjectIdAndIssueTypeId(MapUtil.getLong(conditions, "projectId"), MapUtil.getLong(conditions, "issueTypeId")); for (IssueTypeCustomField issueTypeCustomField : issueTypeCustomFields) { excelInfo.addAttrInfos(new ExportExcelAttrVo("id", issueTypeCustomField.getCustomField().getName(), 10, ExportExcelAttrVo.ALIGN_CENTER)); } } // 엑셀 import 로 이슈를 등록한다. @Override @Transactional public void importExcel(IssueForm issueForm, MultipartFile multipartFile) throws Exception { /*StopWatch serviceStart = new StopWatch(); serviceStart.start();*/ // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(); if (multipartFile != null) { // 업로드 파일 확장자 체크 this.verifyMultipartFileExtension(multipartFile); Map priorityMaps = new HashMap<>(); // 우선 순위 모음 Map severityMaps = new HashMap<>(); // 중요도 모음 Map departmentMaps = new HashMap<>(); // 부서 모음 Map customFieldMaps = new HashMap<>(); Map issueNumberMaps = new HashMap<>(); // 이슈 번호 모음 Map issueTypeCustomFieldMaps = new HashMap<>(); // 이슈 타입 + 사용자 정의 필드 연결 정보 Map companyFieldMaps = new HashMap<>(); //업체 모음 Map ispFieldMaps = new HashMap<>(); //isp 모음 Map hostingFieldMaps = new HashMap<>(); //호스팅 모음 Workspace workspace = this.workspaceService.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId()); // 이슈를 넣으려는 업무 공간 // 이슈의 주요 속성을 map 에 저장하여 엑셀 import 에서 지정한 대상(이슈 속성)을 빠르게 찾을 수 있게 한다. this.IssueAttributeMapToList(issueForm, priorityMaps, severityMaps, departmentMaps, customFieldMaps, issueTypeCustomFieldMaps, companyFieldMaps, ispFieldMaps, hostingFieldMaps); // 0.237 - 0.230 List issueForms = Lists.newArrayList(); List headers = Lists.newArrayList(); Workbook workbook; workbook = WorkbookFactory.create(multipartFile.getInputStream()); Sheet sheet = workbook.getSheetAt(0); int lastRowNum = sheet.getLastRowNum() + 1; // 2건 - 제목, 헤더 - 성능을 위해 최대 1만건으로 제한 if (lastRowNum > (EXCEL_IMPORT_MAX_ROWS + 2)) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_MAX_ROWS_OVER)); } for (int rowIndex = 0; rowIndex < lastRowNum; rowIndex++) { // 0번은 헤더는 무시한다. Row row = sheet.getRow(rowIndex); // 헤더 정보를 추출한다 - 사용자 정의 필드 정보를 가져오기 위해 if (rowIndex == 1) { for (int cellIndex = 0; cellIndex < row.getLastCellNum(); cellIndex++) { Cell cell = row.getCell(cellIndex); if (cell == null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EXCEL_EMPTY_CELL)); } // 엑셀 import 데이터에서 cell 값을 문자열로 변환한다. String cellValue = CommonUtil.convertExcelStringToCell(cell); if (StringUtils.isEmpty(cellValue)) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EXCEL_HEADER_EMPTY_CELL)); } headers.add(cellValue); } } // 1번 헤더부터 데이터 영역 if (rowIndex > 1) { // 이슈로 등록하기 위해 IssueForm 에 데이터를 셋팅한다. IssueForm newIssueForm = this.setIssueFormToExcelField(row, (rowIndex + 1), priorityMaps, severityMaps, departmentMaps, customFieldMaps, companyFieldMaps, ispFieldMaps, hostingFieldMaps, headers); ConvertUtil.copyProperties(issueForm, newIssueForm); issueForms.add(newIssueForm); } } if (issueForms.size() < 1) { return; } // 1.176 // 이슈 등록 // this.issueMapper.insertBatch(issueForms); for (IssueForm saveIssueForm : issueForms) { Issue issue = new Issue(); ConvertUtil.copyProperties(saveIssueForm, issue); IssueType issueType = this.issueTypeService.getIssueType(saveIssueForm.getIssueTypeId()); Workflow workflow = issueType.getWorkflow(); Project project = this.projectService.getProject(saveIssueForm.getProjectId()); Long issueNumber = this.issueNumberGeneratorService.generateIssueNumber(project); IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(workflow); issue.setPriority(this.priorityService.getPriority(saveIssueForm.getPriorityId())); issue.setSeverity(this.severityService.getSeverity(saveIssueForm.getSeverityId())); issue.setIssueStatus(issueStatus); issue.setIssueType(issueType); issue.setProject(project); issue.setIssueNumber(issueNumber); if (saveIssueForm.getParentIssueId() != null && saveIssueForm.getParentIssueId() > -1) { issue.setParentIssue(this.getIssue(saveIssueForm.getParentIssueId())); } issue = this.issueRepository.saveAndFlush(issue); saveIssueForm.setId(issue.getId()); IssueDepartment issueDepartment = new IssueDepartment(); issueDepartment.setIssue(issue); issueDepartment.setWorkspace(workspace); List departmentsIds = this.workflowDepartmentService.findFirstDepartmentIds(workflow); if (departmentsIds != null && departmentsIds.size() > 0) { for (Long departmentId : departmentsIds) { issueDepartment.setDepartment(this.departmentService.getDepartment(departmentId)); } issue.addIssueDepartment(issueDepartment); } saveIssueForm.setIssueStatusId(issueStatus.getId()); this.setIssuePartners(saveIssueForm, issue); } // 0.416 - 0.439 // 1.373 ~ 1.394 // TODO - 이슈 이력 벌크 등록을 할 경우 프로필 이력 조회에서 부하가 심해서 넣을지 고민해야함. // this.bulkInsertIssueHistory(issueForms); // 이슈 담당자 벌크 등록 this.bulkInsertIssueAssignee(issueForms, workspace); // 0.361 - 0.705 // 1.816 /*StopWatch serviceStart = new StopWatch(); serviceStart.start();*/ // 이슈 사용자 정의 값 필드 벌크 등록 this.bulkInsertIssueCustomFieldValue(issueForms, issueTypeCustomFieldMaps); // 3.628 - 3.445 /*serviceStart.stop(); log.debug("2차 저장 시간 : " + serviceStart.getTime());*/ // 이슈 리스크 벌크 등록 this.bulkInsertIssueRisk(issueForms, workspace); // reverse index 업데이트 this.issueMapper.updateBatch(issueForms); // 증가된 이슈 번호를 업데이트 한다. // issueNumberMaps.put(issueForm.getProjectId(), issueForm.getProjectId()); // this.issueNumberGeneratorService.updateIssueNumber(issueNumberMaps); } } /** * 엑셀로 입력한 파트너 정보 저장 * @param issueForm IssueForm */ private void setIssuePartners(IssueForm issueForm, Issue issue) { IssueCompany issueCompany = new IssueCompany(); IssueIsp issueIsp = new IssueIsp(); IssueHosting issueHosting = new IssueHosting(); //issueCompany 등록 if (issueForm.getIssueCompanyFields() != null && issueForm.getIssueCompanyFields().size() > 0) { for (Map issueCompanyMap : issueForm.getIssueCompanyFields()) { CompanyField companyField = ConvertUtil.convertMapToClass(issueCompanyMap, CompanyField.class); issueCompany = ConvertUtil.convertMapToClass(issueCompanyMap, IssueCompany.class, "id"); issueCompany.setCompanyField(companyField); issueCompany.setIssue(issue); this.issueCompanyRepository.saveAndFlush(issueCompany); // 사용자가 ISP를 직접 입력하지 않았을 경우 업체에 등록되어있는 ISP 설정 if (issueForm.getIssueIspFields() == null || issueForm.getIssueIspFields().size() < 1) { // 업체의 ISP가 있는 경우 issueISP 등록 if (companyField.getIspId() != null && companyField.getIspId() != -1) { IspField ispField = this.ispFieldService.getIsp(companyField.getIspId()); issueIsp = ConvertUtil.copyProperties(ispField, IssueIsp.class, "id"); issueIsp.setIspField(ispField); issueIsp.setIssue(issue); this.issueIspRepository.saveAndFlush(issueIsp); } } // 사용자가 호스팅을 직접 입력하지 않았을 경우 업체에 등록되어있는 호스팅 설정 if (issueForm.getIssueHostingFields() == null || issueForm.getIssueHostingFields().size() < 1) { // 업체의 호스팅이 있는 경우 issueHosting 등록 if (companyField.getHostingId() != null && companyField.getHostingId() != -1) { HostingField hostingField = this.hostingFieldService.getHosting(companyField.getHostingId()); issueHosting = ConvertUtil.copyProperties(hostingField, IssueHosting.class, "id"); issueHosting.setHostingField(hostingField); issueHosting.setIssue(issue); this.issueHostingRepository.saveAndFlush(issueHosting); } } } } //issueIsp 등록 if (issueForm.getIssueIspFields() != null && issueForm.getIssueIspFields().size() > 0) { for (Map issueIspMap : issueForm.getIssueIspFields()) { issueIsp = ConvertUtil.convertMapToClass(issueIspMap, IssueIsp.class, "id"); IspField ispField = ConvertUtil.convertMapToClass(issueIspMap, IspField.class); issueIsp.setIspField(ispField); issueIsp.setIssue(issue); this.issueIspRepository.saveAndFlush(issueIsp); } } //issueHosting 등록 if (issueForm.getIssueHostingFields() != null && issueForm.getIssueHostingFields().size() > 0) { for (Map issueHostingMap : issueForm.getIssueHostingFields()) { issueHosting = ConvertUtil.convertMapToClass(issueHostingMap, IssueHosting.class, "id"); HostingField hostingField = ConvertUtil.convertMapToClass(issueHostingMap, HostingField.class); issueHosting.setHostingField(hostingField); issueHosting.setIssue(issue); this.issueHostingRepository.saveAndFlush(issueHosting); } } } // 업로드 파일 확장자 체크 private void verifyMultipartFileExtension(MultipartFile multipartFile) { multipartFile.getOriginalFilename(); int pos = multipartFile.getOriginalFilename().lastIndexOf("."); String ext = multipartFile.getOriginalFilename().substring(pos + 1); if (!ext.equals("xlsx")) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EXCEL_NOT_EXTENSION)); } } // 이슈 이력 벌크 등록 private void bulkInsertIssueHistory(List issueForms) { List> issueHistoryMaps = Lists.newArrayList(); for (IssueForm issueForm : issueForms) { Map issueHistoryMap = new HashMap<>(); issueHistoryMap.put("issueId", issueForm.getId()); issueHistoryMap.put("projectId", issueForm.getProjectId()); issueHistoryMap.put("registerId", this.webAppUtil.getLoginId()); issueHistoryMap.put("issueHistoryType", IssueHistoryType.ADD.toString()); StringBuilder description = new StringBuilder(); // 이력 테스트 추출 this.issueHistoryService.makeDescription(description, IssueHistoryType.ADD, null); issueHistoryMap.put("description", description.toString()); issueHistoryMaps.add(issueHistoryMap); } // 이슈 이력 벌크 등록 this.issueMapper.insertHistoryBatch(issueHistoryMaps); } // 이슈 담당자 벌크 등록 private void bulkInsertIssueAssignee(List issueForms, Workspace workspace) { List> issueAssigneeMaps = Lists.newArrayList(); for (IssueForm issueForm : issueForms) { for (Long departmentId : issueForm.getDepartmentIds()) { Map issueAssigneeMap = new HashMap<>(); issueAssigneeMap.put("issueId", issueForm.getId()); //issueAssigneeMap.put("userId", userId); issueAssigneeMap.put("departmentId", departmentId); issueAssigneeMap.put("workspaceId", workspace.getId()); issueAssigneeMap.put("registerId", this.webAppUtil.getLoginId()); issueAssigneeMaps.add(issueAssigneeMap); } } if (issueAssigneeMaps.size() > 0) { // 이슈 담당자 벌크 등록 //this.issueUserService.insertIssueUser(issueAssigneeMaps); this.issueDepartmentService.insertIssueDepartment(issueAssigneeMaps); } } // 이슈 리스크 벌크 등록 private void bulkInsertIssueRisk(List issueForms, Workspace workspace) { List> issueRiskMaps = Lists.newArrayList(); for (IssueForm issueForm : issueForms) { Map issueRiskMap = new HashMap<>(); issueRiskMap.put("issueId", issueForm.getId()); issueRiskMap.put("changeAssigneeCount", 0L); issueRiskMap.put("changeDepartmentCount", 0L); issueRiskMap.put("changeIssueStatusCount", 0L); issueRiskMap.put("workspaceId", workspace.getId()); issueRiskMap.put("issueStatusIds", issueForm.getIssueStatusId()); issueRiskMap.put("registerId", this.webAppUtil.getLoginId()); issueRiskMaps.add(issueRiskMap); } if (issueRiskMaps.size() > 0) { // 이슈 리스크 벌크 등록 this.issueMapper.insertIssueRiskBatch(issueRiskMaps); } } // 이슈 사용자 정의 필드 선택 값 벌크 등록 private void bulkInsertIssueCustomFieldValue(List issueForms, Map issueTypeCustomFieldMaps) { List> issueCustomFieldValueMaps = Lists.newArrayList(); for (IssueForm issueForm : issueForms) { for (Map issueCustomField : issueForm.getIssueCustomFields()) { String findKey = issueForm.getIssueTypeId().toString() + MapUtil.getString(issueCustomField, "customFieldId"); // 이슈 타입 + 사용자 정의 필드 연결정보가 없다면 저장하지 않는다. if (issueTypeCustomFieldMaps.get(findKey) == null) { continue; } issueCustomField.put("issueTypeCustomFieldId", issueTypeCustomFieldMaps.get(findKey)); issueCustomField.put("issueId", issueForm.getId()); issueCustomField.put("registerId", this.webAppUtil.getLoginId()); issueCustomFieldValueMaps.add(issueCustomField); } // 엑셀에 업체명을 입력하지 않았을 경우 같은 도메인 업체 찾기 if (issueForm.getIssueCompanyFields() == null || issueForm.getIssueCompanyFields().size() < 1) { // 같은 도메인 업체 찾기 IssueForm partners = this.findCompanyField(issueForm); Issue issue = this.findOne(issueForm.getId()); if (partners.getIssueCompanyFields() != null && partners.getIssueCompanyFields().size() > 0) { for (Map company : partners.getIssueCompanyFields()) { IssueCompany issueCompany = ConvertUtil.convertMapToClass(company, IssueCompany.class); CompanyField companyField = ConvertUtil.convertMapToClass(company, CompanyField.class); issueCompany.setCompanyField(companyField); issueCompany.setIssue(issue); this.issueCompanyRepository.saveAndFlush(issueCompany); } } if (partners.getIssueIspFields() != null && partners.getIssueIspFields().size() > 0) { for (Map isp : partners.getIssueIspFields()) { IssueIsp issueIsp = ConvertUtil.convertMapToClass(isp, IssueIsp.class); IspField ispField = ConvertUtil.convertMapToClass(isp, IspField.class); issueIsp.setIspField(ispField); issueIsp.setIssue(issue); this.issueIspRepository.saveAndFlush(issueIsp); } } if (partners.getIssueHostingFields() != null && partners.getIssueHostingFields().size() > 0) { for (Map hosting : partners.getIssueHostingFields()) { IssueHosting issueHosting = ConvertUtil.convertMapToClass(hosting, IssueHosting.class); HostingField hostingField = ConvertUtil.convertMapToClass(hosting, HostingField.class); issueHosting.setHostingField(hostingField); issueHosting.setIssue(issue); this.issueHostingRepository.saveAndFlush(issueHosting); } } } } if (issueCustomFieldValueMaps.size() > 0) { this.issueMapper.insertIssueCustomFieldValueBatch(issueCustomFieldValueMaps); } } // 이슈의 주요 속성을 map 에 저장하여 엑셀 import 에서 지정한 대상(이슈 속성)을 빠르게 찾을 수 있게 한다. private void IssueAttributeMapToList(IssueForm issueForm, Map priorityMaps, Map severityMaps, Map departmentMaps, Map customFieldMaps,Map issueTypeCustomFieldMaps, Map companyFieldMaps, Map ispFieldMaps, Map hostingFieldMaps) { Project project = this.projectService.getProject(issueForm.getProjectId()); for (IssueTypeCustomField issueTypeCustomField : project.getIssueTypeCustomFields()) { // 빠르게 찾기 위해 이슈 타입 아이디 + 사용자 정의 필드 아이디를 키로 한다. String makeKey = issueTypeCustomField.getIssueType().getId().toString() + issueTypeCustomField.getCustomField().getId().toString(); issueTypeCustomFieldMaps.put(makeKey, issueTypeCustomField.getId()); } // 우선순위를 바로 찾을 수 있게 준비 List priorities = this.priorityService.findByWorkspaceId(); for (Priority priority : priorities) { priorityMaps.put(priority.getName(), priority); } // 중요도를 바로 찾을 수 있게 준비 List severities = this.severityService.findByWorkspaceId(); for (Severity severity : severities) { severityMaps.put(severity.getName(), severity); } // 사용자 정의 필드를 바로 찾을 수 있게 준비 List customFields = this.customFieldService.findByWorkspaceId(); for (CustomField customField : customFields) { customFieldMaps.put(customField.getName(), customField); } // 업체 정보를 바로 찾을 수 있게 준비 List companyFields = this.companyFieldService.findAll(); for (CompanyField companyField : companyFields) { companyFieldMaps.put(companyField.getName(), companyField); } // ISP 정보를 바로 찾을 수 있게 준비 List ispFields = this.ispFieldService.findAll(); for (IspField ispField : ispFields) { ispFieldMaps.put(ispField.getName(), ispField); } // 호스팅 정보를 바로 찾을 수 있게 준비 List hostingFields = this.hostingFieldService.findAll(); for (HostingField hostingField : hostingFields) { hostingFieldMaps.put(hostingField.getName(), hostingField); } } /** * cell NULL 체크 함수 * 문자형식 cell 체크 * @param cell Cell * @return boolean */ private Boolean cellNullCheck (Cell cell) { if (cell != null ) { if (cell.getCellType() != Cell.CELL_TYPE_BLANK) { if (cell.getCellType() == Cell.CELL_TYPE_STRING && cell.getStringCellValue() != null) { return false; } } } return true; } // 엑셀 필드에 있는 정보를 이슈 form 으로 옮긴다. private IssueForm setIssueFormToExcelField(Row row, int rowIndex, Map priorityMaps, Map severityMaps, Map departmentMaps, Map customFieldMaps, Map companyFieldMaps, Map ispFieldMaps, Map hostingFieldMaps, List headers) throws ParseException { IssueForm issueForm = new IssueForm(); issueForm.setRegisterId(this.webAppUtil.getLoginId()); Project project = null; // 제목, 내용, 프로젝트 키, 이슈 타입, 우선순위, 중요도, 담당자, 시작일, 종료일, 사용자 정의 필드 for (int cellIndex = 0; cellIndex < headers.size(); cellIndex++) { Cell cell = row.getCell(cellIndex); boolean isNull = cellNullCheck(cell); String cellStr = ""; if (!isNull) { cellStr = CommonUtil.convertExcelStringToCell(cell); // 공백 제거 cell.setCellValue(cellStr.trim()); } else { cell.setCellValue(cellStr); } switch (cellIndex) { case 0: // 이슈 제목을 IssueForm 에 저장한다. if (isNull) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISSUE_TITLE_IS_NULL, rowIndex)); } this.setIssueFormTitle(cellStr, issueForm, rowIndex); break; case 1: // 내용 issueForm.setDescription(cellStr); break; case 2: // 우선순위를 IssueForm 에 저장한다. if (isNull) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PRIORITY_IS_NULL, rowIndex)); } this.setIssueFormPriority(cellStr, priorityMaps, issueForm, rowIndex); break; case 3: // 중요도를 IssueForm 에 저장한다. if (isNull) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_SEVERITY_IS_NULL, rowIndex)); } this.setIssueFormSeverity(cellStr, severityMaps, issueForm, rowIndex); break; /*case 6: // 담당자를 IssueForm 에 저장한다. this.setIssueFormAssignee(cell, userMaps, issueForm, project); break;*/ case 4: // 시작일을 IssueForm 에 저장한다. this.setIssueFormPeriod(cellStr, issueForm, true, rowIndex, isNull); break; case 5: // 종료일을 IssueForm 에 저장한다. this.setIssueFormPeriod(cellStr, issueForm, false, rowIndex, isNull); break; case 6: // 업체를 IssueForm 에 저장한다. this.setIssueFormCompanyField(cellStr, companyFieldMaps, issueForm, rowIndex); break; case 7: // ISP를 IssueForm 에 저장한다. this.setIssueFormIspField(cellStr, ispFieldMaps, issueForm, rowIndex); break; case 8: // 호스팅을 IssueForm 에 저장한다. this.setIssueFormHostingField(cellStr, hostingFieldMaps, issueForm, rowIndex); break; default: // 9번 부터는 사용자 정의 필드. 사용자 정의 필드 정보를 IssueForm 에 저장한다. this.setIssueFormCustomFieldValue(cellStr, customFieldMaps, issueForm, headers.get(cellIndex), rowIndex); } } return issueForm; } private void setIssueFormHostingField(String cell, Map hostingFieldMaps, IssueForm issueForm, int rowIndex) { if (cell.length() > 0) { Map issueHostingFields = new HashMap<>(); HostingField hostingFieldMap = hostingFieldMaps.get(cell); if (hostingFieldMap == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_HOSTING_NOT_EXIST, rowIndex)); } ConvertUtil.copyProperties(hostingFieldMap, issueHostingFields); issueForm.addIssueHostingField(issueHostingFields); } } private void setIssueFormIspField(String cell, Map ispFieldMaps, IssueForm issueForm, int rowIndex) { if (cell.length() > 0) { Map issueIspFields = new HashMap<>(); IspField ispFieldMap = ispFieldMaps.get(cell); if (ispFieldMap == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_ISP_NOT_EXIST, rowIndex)); } ConvertUtil.copyProperties(ispFieldMap, issueIspFields); issueForm.addIssueIspField(issueIspFields); } } private void setIssueFormCompanyField(String cell, Map companyFieldMaps, IssueForm issueForm, int rowIndex) { if (cell.length() > 0) { Map issueCompanyFields = new HashMap<>(); CompanyField companyFieldMap = companyFieldMaps.get(cell); if (companyFieldMap == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_COMPANY_NOT_EXIST, rowIndex)); } ConvertUtil.copyProperties(companyFieldMap, issueCompanyFields); issueForm.addissueCompanyField(issueCompanyFields); } } // 이슈 제목을 IssueForm 에 저장한다. private void setIssueFormTitle(String title, IssueForm issueForm, int rowIndex) { // 제목 유효성 체크 this.verifyTitle(title); issueForm.setTitle(title); } // 프로젝트 아이디를 IssueForm 에 저장한다. private Project setIssueFormProject(Cell cell, Map projectMaps, IssueForm issueForm, int rowIndex) { if (cell == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PROJECT_KEY_IS_NULL, rowIndex)); } Project project = projectMaps.get(CommonUtil.convertExcelStringToCell(cell).toUpperCase()); if (project == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PROJECT_NOT_EXIST, rowIndex)); } issueForm.setProjectId(project.getId()); return project; } // 이슈 고유 번호를 IssueForm 에 저장한다. private void setIssueFormIssueNumber(IssueForm issueForm, Map issueNumberMaps, Project project, int rowIndex) { // 이슈 고유 번호 Long issueNumber = issueNumberMaps.get(project.getId()); if (issueNumber == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NUMBER_NOT_EXIST, rowIndex)); } issueForm.setIssueNumber(issueNumber); issueNumberMaps.put(project.getId(), ++issueNumber); // 이슈 번호를 1씩 증가 시킨다. } // 우선순위를 IssueForm 에 저장한다. private void setIssueFormPriority(String priorityStr, Map priorityMaps, IssueForm issueForm, int rowIndex) { Priority priority = priorityMaps.get(priorityStr); if (priority == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PRIORITY_NOT_EXIST, rowIndex)); } issueForm.setPriorityId(priority.getId()); } // 중요도를 IssueForm 에 저장한다. private void setIssueFormSeverity(String strSeverity, Map severityMaps, IssueForm issueForm, int rowIndex) { Severity severity = severityMaps.get(strSeverity); if (severity == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_SEVERITY_NOT_EXIST, rowIndex)); } issueForm.setSeverityId(severity.getId()); } private void setIssueFormAssignee(Cell cell, Map userMaps, IssueForm issueForm, Project project) { if (cell != null) { String[] splitAssignee = CommonUtil.convertExcelStringToCell(cell).split("#"); Map userMap = (Map) MapUtil.getObject(userMaps, project.getProjectKey()); List userIds = Lists.newArrayList(); for (String account : splitAssignee) { if (MapUtil.getLong(userMap, account) != null) { userIds.add(MapUtil.getLong(userMap, account)); } } issueForm.setUserIds(userIds); } } // 시작일, 종료일을 IssueForm 에 저장한다. private void setIssueFormPeriod(String periodDate, IssueForm issueForm, Boolean checkStartDate, int rowIndex, boolean isNull) throws ParseException { if (!isNull) { Date startDate = DateUtil.convertStrToDateOnly(periodDate); if (startDate == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALIDITY_EMPTY, rowIndex)); } if (checkStartDate) { issueForm.setStartDate(periodDate); } else { issueForm.setCompleteDate(periodDate); // 종료일만 입력 했을 경우 if (issueForm.getCompleteDate() != null && issueForm.getStartDate() == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALIDITY_EMPTY_START, rowIndex)); } try { // 날짜 유효성 체크 this.checkStartCompleteDate(issueForm.getStartDate(), issueForm.getCompleteDate()); } catch (OwlRuntimeException e) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_PERIOD_NOT_VALIDITY, rowIndex)); } } } } // 사용자 정의 필드 정보를 IssueForm 에 저장한다.- private void setIssueFormCustomFieldValue(String cellValue, Map customFieldMaps, IssueForm issueForm, String customFieldName, int rowIndex) { Map issueCustomFieldMap = new HashMap<>(); CustomField customField = customFieldMaps.get(customFieldName); if (customField == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_HEADER_CUSTOM_FIELD_NOT_EXIST, rowIndex)); } // 사용자 정의 필드 값이 공백이면 중지 if (StringUtils.isEmpty(cellValue)) { return; } boolean validity = false; switch (customField.getCustomFieldType()) { case INPUT: case NUMBER: case DATETIME: case IP_ADDRESS: case EMAIL: case SITE: case TEL: if (customField.getCustomFieldType() != INPUT && cellValue.length() > 100) { //INPUT 타입은 100자 제한 없음 throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.CUSTOM_FIELD_TEXT_TYPE_MAX_LENGTH_OUT)); } if (customField.getCustomFieldType() == DATETIME) { //DATETIME일 경우 format 변경 Date date = DateUtil.convertStrToDate(cellValue); if (date == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_DATETIME_NOT_DASH, rowIndex)); } } issueCustomFieldMap.put("customFieldId", customField.getId()); issueCustomFieldMap.put("useValue", cellValue); issueForm.addIssueCustomFields(issueCustomFieldMap); break; case SINGLE_SELECT: // 값 유효성 체크 for (CustomFieldValue customFieldValue : customField.getCustomFieldValues()) { if (customFieldValue.getValue().equals(cellValue)) { validity = true; break; } } if (!validity) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_CUSTOM_FIELD_VALUE_NOT_VALIDITY, rowIndex)); } issueCustomFieldMap.put("customFieldId", customField.getId()); issueCustomFieldMap.put("useValue", cellValue); issueForm.addIssueCustomFields(issueCustomFieldMap); break; case MULTI_SELECT: // 값 유효성 체크 String[] useValues = cellValue.split("#"); // 해, 달 for (String useValue : useValues) { for (CustomFieldValue customFieldValue : customField.getCustomFieldValues()) { if (customFieldValue.getValue().equals(useValue)) { validity = true; Map multiValueMap = new HashMap<>(); multiValueMap.put("customFieldId", customField.getId()); multiValueMap.put("useValue", useValue); issueForm.addIssueCustomFields(multiValueMap); } } } if (!validity) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.EXCEL_CUSTOM_FIELD_VALUE_NOT_VALIDITY, rowIndex)); } break; } } // 프로젝트에 있는 모든 이슈 정보를 조회한다. @Override @Transactional(readOnly = true) public List findByProjectId(Long projectId) { List> issueMaps = this.issueMapper.findByProjectId(projectId); List issueIds = Lists.newArrayList(); for (Map issueMap : issueMaps) { Long issueId = MapUtil.getLong(issueMap, "id"); if (issueId != null) { issueIds.add(issueId); } } return issueIds; } // 이슈를 대상자들에게 메일로 발송한다. @Override @Transactional(readOnly = true) public void sendIssueEmail(IssueForm issueForm) { if (issueForm.getSendEmails().size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER)); }else if (issueForm.getTemplate() != null){ throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE)); } Issue issue = this.getIssue(issueForm.getId()); Map issueMap = new HashMap<>(); // 이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다. this.makeIssueMapToIssue(issue, issueMap); // 발신자 표시 UserVo toUser = this.webAppUtil.getLoginUser(); issueMap.put("toUser", toUser.getName() + "(" + CommonUtil.decryptAES128(toUser.getAccount()) + ")"); // 이슈 링크 String projectKey = issue.getProject().getProjectKey(); Long IssueNumber = issue.getIssueNumber(); String link = this.configuration.getEmailSendUrl() + "/#/issues/issueList?projectKey=" + projectKey + "&issueNumber=" + IssueNumber.toString(); issueMap.put("issueLink", link); issueMap.put("projectLink", link); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL)); this.systemEmailService.directEmail(issueForm.getSendEmails().toArray(new String[issueForm.getSendEmails().size()]), EmailType.ISSUE_SEND, issueMap, null); } // 이슈를 템플릿에 따라 파트너 담당자에게 메일로 발송한다. @Override @Transactional(readOnly = true) public void sendIssueEmailPartners(EmailTemplateForm emailTemplateForm, List multipartFiles) { if (emailTemplateForm.getSendEmails().size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER)); }else if (emailTemplateForm.getTemplate() == null){ throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE)); } else if (emailTemplateForm.getIssueId() == null) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST)); } Issue issue = this.getIssue(emailTemplateForm.getIssueId()); // 발신자 표시 User user = this.webAppUtil.getLoginUserObject(); UserVo toUser = this.webAppUtil.getLoginUser(); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL)); StringBuilder sb = new StringBuilder(); Locale locale = CommonUtil.getUserLanguage(user.getLanguage()); String[] sendMails = ConvertUtil.ToArray(emailTemplateForm.getSendEmails()); for(int i=0; i < sendMails.length; i++) { sendMails[i] = CommonUtil.decryptAES128(sendMails[i]); } this.systemEmailService.sendEmail(emailTemplateForm.getTitle(), emailTemplateForm.getTemplate(), sendMails, null, multipartFiles); this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, emailTemplateForm.getSendEmails(), sb); this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString()); } @Override public void sendCommonEmail(EmailCommonForm emailCommonForm, List multipartFiles) { if (emailCommonForm.getSendEmails().size() < 1) { throw new OwlRuntimeException( this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER)); } Issue issue = null; if(emailCommonForm.getIssueId() != null) { issue = this.getIssue(emailCommonForm.getIssueId()); } // 발신자 표시 User user = this.webAppUtil.getLoginUserObject(); UserVo toUser = this.webAppUtil.getLoginUser(); // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL)); StringBuilder sb = new StringBuilder(); Locale locale = CommonUtil.getUserLanguage(user.getLanguage()); String[] sendMails = ConvertUtil.ToArray(emailCommonForm.getSendEmails()); for(int i=0; i < sendMails.length; i++) { sendMails[i] = CommonUtil.decryptAES128(sendMails[i]); } this.systemEmailService.sendEmail(emailCommonForm.getTitle(), emailCommonForm.getDescription(), sendMails, null, multipartFiles); if (issue != null) { this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, emailCommonForm.getSendEmails(), sb); this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString()); } } // 예약 발생 이슈를 실행한다 @Override @Transactional public void reservationIssue() { List issueReservations = this.issueReservationService.findByIssueReservationTypeNotNull(); Calendar calendar = Calendar.getInstance(); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); int month = calendar.get(Calendar.MONTH) + 1; int date = calendar.get(Calendar.DATE); for (IssueReservation issueReservation : issueReservations) { switch (issueReservation.getIssueReservationType()) { case DAY: // 이슈를 다시 생성 상태로 변경시킨다. this.occurReservationIssue(issueReservation.getIssue()); break; case WEEK: if (dayOfWeek == Integer.parseInt(issueReservation.getReservation())) { // 이슈를 다시 생성 상태로 변경시킨다. this.occurReservationIssue(issueReservation.getIssue()); } break; case MONTH: if (date == Integer.parseInt(issueReservation.getReservation())) { // 이슈를 다시 생성 상태로 변경시킨다. this.occurReservationIssue(issueReservation.getIssue()); } break; case YEAR: String[] reservations = issueReservation.getReservation().split("-"); if (reservations.length > 1) { if ((Integer.parseInt(reservations[0]) == month) && Integer.parseInt(reservations[1]) == date) { // 이슈를 다시 생성 상태로 변경시킨다. this.occurReservationIssue(issueReservation.getIssue()); } } break; } } } // 이슈를 다시 생성 상태로 변경시킨다. private void occurReservationIssue(Issue issue) { if (!issue.getIssueStatus().getIssueStatusType().equals(IssueStatusType.READY)) { // 이슈를 생성 상태로 변경시킨다. IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issue.getIssueType().getWorkflow()); if (issueStatus != null) { StringBuilder detectIssueChange = new StringBuilder(); // 예약 발생으로 이슈 상태 변경된 정보를 기록한다. this.issueHistoryService.detectReservationIssueStatus(issue, detectIssueChange, issueStatus); issue.setIssueStatus(issueStatus); this.issueRepository.saveAndFlush(issue); // 이슈 상태 변경 정보를 이력으로 남긴다. this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, detectIssueChange.toString()); // 이슈 버전 생성 this.issueVersionService.addIssueVersion(issue); } } } @Autowired private ProjectMapper projectMapper; @Override @Transactional(readOnly = true) public Map findTask(IssueCondition taskCondition) { StopWatch serviceStart = new StopWatch(); serviceStart.start(); ProjectCondition projectCondition = new ProjectCondition(this.webAppUtil.getLoginUser().getLastProjectId(), this.webAppUtil.getLoginId()); List> checkProjectRole = this.projectMapper.checkIncludeProject(projectCondition); if (checkProjectRole.size() < 1) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.PROJECT_NOT_INCLUDE_USER)); } // 이중으로 역할 체크를 해서 참여하지 않은 사용자가 해당 프로젝트에 접근 못하도록 한다. taskCondition.setLoginUserId(this.webAppUtil.getLoginId()); // List> results = this.taskMapper.find(taskCondition); List> results = this.issueMapper.find(taskCondition); serviceStart.stop(); long executeTime = serviceStart.getTime(); Map tasks = new HashMap<>(); // 워크플로우 상태 id 를 키로 만든다. for (Long workflowStatusId : taskCondition.getStatusIds()) { tasks.put(workflowStatusId.toString(), Lists.newArrayList()); } Map taskUserSave = new HashMap<>(); // 전체 task_id를 모은다. for (Map result : results) { Long taskId = MapUtil.getLong(result, "id"); taskCondition.addIssueIds(taskId.toString()); // 각 task_id 별로 사용자 정보를 저장할 공간을 미리 확보한다. taskUserSave.put(taskId.toString(), Lists.newArrayList()); } List> taskDepartments = Lists.newArrayList(); // task 가 하나도 없을 경우에는 조회를 하지 않는다. if (!taskCondition.getIssueIds().isEmpty()) { //taskUsers = this.issueMapper.getAllTaskUser(taskCondition); taskDepartments = this.issueMapper.getAllTaskUser(taskCondition); } // task_id 에 매칭되는 담당자 정보를 준비한다. /*for (Map taskUser : taskUsers) { Long taskId = MapUtil.getLong(taskUser, "taskId"); List userVos = (List)taskUserSave.get(taskId.toString()); userVos.add(ConvertUtil.convertMapToClass(taskUser, UserVo.class)); }*/ for (Map taskDepartment : taskDepartments) { Long taskId = MapUtil.getLong(taskDepartment, "taskId"); List departmentVos = (List)taskUserSave.get(taskId.toString()); departmentVos.add(ConvertUtil.convertMapToClass(taskDepartment, DepartmentVo.class)); } for (Map result : results) { IssueVo taskVo = ConvertUtil.convertMapToClass(result, IssueVo.class); // 중요도 셋팅 if (MapUtil.getLong(result, "priorityId") != null) { PriorityVo priorityVo = new PriorityVo(); priorityVo.setId(MapUtil.getLong(result, "priorityId")); priorityVo.setName(MapUtil.getString(result, "priorityName")); priorityVo.setColor(MapUtil.getString(result, "priorityColor")); taskVo.setPriorityVo(priorityVo); } // 워크플로우 상태 셋팅 if (MapUtil.getLong(result, "workflowStatusId") != null) { WorkflowStatusVo workflowStatusVo = new WorkflowStatusVo(); workflowStatusVo.setId(MapUtil.getLong(result, "workflowStatusId")); workflowStatusVo.setName(MapUtil.getString(result, "workflowStatusName")); workflowStatusVo.setColor(MapUtil.getString(result, "workflowStatusColor")); taskVo.setWorkflowStatusVo(workflowStatusVo); } // 담당자 셋팅 //List userVos = (List)taskUserSave.get(taskVo.getId().toString()); //taskVo.setUserVos(userVos); // 담당부서 세팅 List departmentVos = (List)taskUserSave.get(taskVo.getId().toString()); taskVo.setDepartmentVos(departmentVos); List taskVos = (List)tasks.get(MapUtil.getString(result, "workflowStatusId")); taskVos.add(taskVo); tasks.put(MapUtil.getString(result, "workflowStatusId"), taskVos); } /*serviceStart.stop(); long executeTime = serviceStart.getTime();*/ return tasks; } @Transactional @Override public void modifyParentIssue(IssueForm issueDownForm) { //Issue issue = this.getIssue(issueDownForm.getId()); //하위 이슈 Long newParentIssueId = issueDownForm.getParentIssueId(); //변경할 하위이슈의 상위이슈 StringBuilder sb = new StringBuilder(); for (Long downId : issueDownForm.getIds()) { Issue issue = this.getIssue(downId); Issue parentIssue = issue.getParentIssue(); //변경 전 하위이슈의 상위이슈 if(parentIssue != null && parentIssue.getId().equals(newParentIssueId)){ //변경 전 하위이슈의 상위이슈가 존재 할 경우 this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb); this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); } if (newParentIssueId != null) { // 추가 할 경우 parentIssue = this.getIssue(newParentIssueId); //상위이슈(myIssue) issue.setParentIssue(parentIssue); //myIssue를 하위이슈의 상위이슈로 set this.issueHistoryService.detectDownIssues(IssueHistoryType.ADD, issue, sb); //issue = 하위이슈 } else{ // 삭제 할 경우 this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb); issue.setParentIssue(null); } this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); //parentIssue = myIssue(기록은 현재 상세페이지에 해야하니까) this.issueRepository.saveAndFlush(issue); } } @Override public void findPartner(Map resJsonData, Map params) { Long issueTypeId = MapUtil.getLong(params, "issueTypeId"); List usePartnerVos = Lists.newArrayList(); Integer using = 0; if (issueTypeId != null) { IssueType issueType = this.issueTypeService.getIssueType(issueTypeId); // 이슈의 이슈유형 객체 using = issueType.getUsePartner() != null ? issueType.getUsePartner().intValue() : 0; // 이슈유형별로 사용중인 업체/ISP/호스팅 값 } else { for (int partner : UsePartner.partners) { using += partner; } } for (Integer usePartner : UsePartner.partners) { //1(업체), 2(ISP), 4(호스팅) UsePartnerVo usePartnerVo = UsePartner.checkUsePartner(using, usePartner); if (usePartnerVo != null) { usePartnerVos.add(usePartnerVo); } } resJsonData.put(Constants.RES_KEY_CONTENTS, usePartnerVos); } @Override public void findReadyDepartments(Map resJsonData, DepartmentCondition condition, Pageable pageable) { IssueType issueType = this.issueTypeService.getIssueType(condition.getIssueTypeId()); if (issueType != null) { // 이슈 상태 유형이 '대기' 인 이슈 상태 가져오기 IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow()); condition.setIssueStatusId(issueStatus.getId()); condition.setWorkflowId(issueType.getWorkflow().getId()); } List> departmentVos = this.departmentMapper.findByIssueStatusId(condition); resJsonData.put(Constants.RES_KEY_CONTENTS, departmentVos); } }