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.util.*;
|
|
import static kr.wisestone.owl.domain.enumType.CustomFieldType.*;
|
|
@Service
|
public class IssueServiceImpl extends AbstractServiceImpl<Issue, Long, JpaRepository<Issue, Long>> 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<Issue, Long> 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<Long> 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<CustomFieldApiOverlap> 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<Issue> issues = this.findIssue(issueApiForm, issueForm, 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());
|
// 같은 도메인 업체 찾기
|
|
// api 입력값 적용
|
ConvertUtil.copyProperties(issueApiForm, issueForm);
|
|
return issueForm;
|
|
} else {
|
throw new ApiAuthException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR));
|
}
|
}
|
|
/**
|
* 도메인이 동일한 업체 찾기
|
* @param issueForm IssueForm
|
* @return IssueForm
|
*/
|
private IssueForm findCompanyField(IssueForm issueForm) {
|
if(issueForm.getIssueCustomFields() != null && issueForm.getIssueCustomFields().size() > 0) {
|
CompanyFieldCondition condition = new CompanyFieldCondition();
|
List<Map<String, Object>> companyFields = Lists.newArrayList();
|
List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
|
List<Map<String, Object>> issueIspFields = Lists.newArrayList();
|
List<Map<String, Object>> issueHostingFields = Lists.newArrayList();
|
|
for (Map<String, Object> issueCustomField : issueForm.getIssueCustomFields()) {
|
Long customFieldId = MapUtil.getLong(issueCustomField, "customFieldId");
|
CustomField customField = this.customFieldService.getCustomField(customFieldId);
|
if(customField != null && customField.getCustomFieldType().equals(SITE) && customField.getName().equals("도메인")) {
|
String useValue = issueCustomField.get("useValue").toString();
|
String[] urlArr = null;
|
List<String> urls = Lists.newArrayList();
|
if (useValue.contains(",")) {
|
urlArr = useValue.split(",");
|
urls.addAll(Arrays.asList(urlArr));
|
} else {
|
urls.add(useValue);
|
}
|
condition.setUrl(urls);
|
companyFields = this.companyFieldService.find(condition);
|
|
if(companyFields != null && companyFields.size() > 0) {
|
for (Map<String, Object> companyField : companyFields) {
|
CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
|
companyField.put("companyId", companyField.get("id"));
|
issueCompanyFields.add(companyField);
|
if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
|
Map<String, Object> 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<String, Object> 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;
|
}
|
|
/**
|
* 조건에 맞는 파트너 정보 찾기
|
* @param condition CompanyFieldCondition
|
* @param issueCompanyFields List<Map<String, Object>>
|
* @param issueIspFields List<Map<String, Object>>
|
* @param issueHostingFields List<Map<String, Object>>
|
*/
|
private void findPartner(CompanyFieldCondition condition, List<Map<String, Object>> issueCompanyFields
|
, List<Map<String, Object>> issueIspFields, List<Map<String, Object>> issueHostingFields) {
|
|
List<Map<String, Object>> companyFields = this.companyFieldService.find(condition);
|
|
if(companyFields != null && companyFields.size() > 0) {
|
for (Map<String, Object> companyField : companyFields) {
|
CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
|
companyField.put("companyId", companyField.get("id"));
|
issueCompanyFields.add(companyField);
|
if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
|
Map<String, Object> 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<String, Object> hostingField = this.hostingFieldService.find(companyFieldVo.getHostingId());
|
if (hostingField != null) {
|
hostingField.put("hostingId", hostingField.get("id"));
|
issueHostingFields.add(hostingField);
|
}
|
}
|
}
|
}
|
}
|
|
private User convertToUser(String token) {
|
// 토큰으로 유저 정보 가져오기
|
UserVo userVo = this.apiTokenService.certification(token);
|
|
// 해당 유저 정보가 현재 db에 있는지 확인
|
return this.userService.getUser(userVo.getId());
|
}
|
|
|
// API 를 통해 이슈 추가.
|
@Override
|
@Transactional
|
public List<Issue> addApiIssue(IssueApiForm issueApiForm) throws CloneNotSupportedException {
|
User user = convertToUser(issueApiForm.getToken());
|
IssueForm issueForm = this.convertToIssueForm(issueApiForm, user);
|
|
List<Issue> 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<Issue> findIssue(IssueApiForm issueApiform, IssueForm issueForm, List<CustomFieldApiOverlap> customFieldApiOverlaps, Long userId) {
|
List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
|
List<Issue> resultIssueVos = Lists.newArrayList();
|
String comma = ",";
|
|
if (issueCustomFieldValueForms.size() > 0) {
|
String concatUseValue = "";
|
int useIdx = 0;
|
int cntIp = 0;
|
int cntSite = 0;
|
|
IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator();
|
Collections.sort(issueCustomFieldValueForms, comp);
|
|
List<String> userValues = Lists.newArrayList();
|
CompanyFieldCondition condition = new CompanyFieldCondition();
|
List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
|
List<Map<String, Object>> issueIspFields = Lists.newArrayList();
|
List<Map<String, Object>> issueHostingFields = Lists.newArrayList();
|
|
for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
|
userValues.add(issueCustomFieldValueForm.getUseValue());
|
|
for(CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
|
if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) {
|
|
String useValue = issueCustomFieldValueForm.getUseValue();
|
if (useValue.contains(" ")) {
|
useValue = useValue.replace(" ","");
|
}
|
|
if (customFieldApiOverlap.getCustomField().getCustomFieldType().equals(IP_ADDRESS)) {
|
long ip = ConvertUtil.ipToLong(useValue);
|
if (cntIp == 0){
|
condition.setIp(ip);
|
}
|
cntIp ++;
|
}
|
|
if(customFieldApiOverlap.getCustomField().getCustomFieldType().equals(SITE)) {
|
String[] urlArr = null;
|
List<String> urls = Lists.newArrayList();
|
if (useValue.contains(",")) {
|
urlArr = useValue.split(",");
|
urls.addAll(Arrays.asList(urlArr));
|
} else {
|
urls.add(useValue);
|
}
|
if (cntSite == 0) {
|
condition.setUrl(urls);
|
}
|
cntSite ++;
|
}
|
|
if (useIdx > 0) {
|
concatUseValue = concatUseValue.concat(comma);
|
}
|
concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue());
|
useIdx++;
|
}
|
}
|
}
|
|
// 추가 할 url or ip에 포함되어있는 파트너 찾기
|
this.findPartner(condition, issueCompanyFields, issueIspFields, issueHostingFields);
|
|
issueForm.setIssueCompanyFields(issueCompanyFields);
|
issueForm.setIssueIspFields(issueIspFields);
|
issueForm.setIssueHostingFields(issueHostingFields);
|
|
IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
|
issueCustomFieldValueCondition.setUseValue(concatUseValue);
|
issueCustomFieldValueCondition.setUseValues(userValues);
|
issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId());
|
// issueCustomFieldValueCondition.setIssueStatusType("CLOSE");
|
List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
|
if (results != null && results.size() > 0) {
|
for (Map<String, Object> result : results) {
|
resultIssueVos.add(this.getIssue(MapUtil.getLong(result, "id")));
|
}
|
}
|
}
|
return resultIssueVos;
|
}
|
|
// 이슈를 생성한다.
|
@Override
|
@Transactional
|
public Issue addIssue(IssueForm issueForm, List<MultipartFile> multipartFiles) {
|
User user = this.webAppUtil.getLoginUserObject();
|
return addIssue(user, issueForm, multipartFiles);
|
}
|
|
// 이슈를 생성한다.
|
@Override
|
@Transactional
|
public Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> 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);
|
|
// 상위 이슈가 종료일경우 대기로 변경
|
IssueStatus parentIssueStatus = parentIssue.getIssueStatus();
|
if (parentIssueStatus.getIssueStatusType().equals(IssueStatusType.CLOSE)) {
|
parentIssue.setIssueStatus(issueStatus);
|
}
|
}
|
|
issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project)); // 각 프로젝트의 고유 이슈 번호 생성
|
|
issue = this.issueRepository.saveAndFlush(issue);
|
|
issue.setReverseIndex(issue.getId() * -1); // 쿼리 속도 개선을 위해 리버스 인덱스 생성
|
|
if (issueForm.getParentIssueId() != null){
|
Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
|
if (issueForm.getIsApi().equals(Issue.IS_API_YES)
|
|| (issueForm.getInheritYn() != null && issueForm.getInheritYn())) {
|
// 하위이슈에 상위이슈의 파트너 정보 적용
|
this.inheritPartners(issue, parentIssue);
|
}
|
}
|
|
// 담당자 지정
|
//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<Map<String, Object>> 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<MultipartFile> multipartFiles) {
|
User user = this.webAppUtil.getLoginUserObject();
|
return addRelIssue(user, issueForm, multipartFiles);
|
}
|
|
// 하위이슈를 생성한다.
|
@Override
|
@Transactional
|
public Issue addDownIssue(Map<String, Object> resJsonData, IssueForm issueForm, List<MultipartFile> multipartFiles) {
|
User user = this.webAppUtil.getLoginUserObject();
|
return addDownIssue(resJsonData, user, issueForm, multipartFiles);
|
}
|
|
// 하위이슈를 생성한다.
|
@Override
|
@Transactional
|
public Issue addDownIssue(Map<String, Object> resJsonData, User user, IssueForm issueForm, List<MultipartFile> 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<Map<String, Object>> 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));
|
|
IssueVo issueVo = this.convertToIssueVo(issue);
|
resJsonData.put(Constants.RES_KEY_CONTENTS, issueVo);
|
|
return issue;
|
}
|
|
/**
|
* Issue를 IssueVo로 변환(하위이슈의 파트너 정보 상속 시 필요)
|
* @param issue Issue
|
* @return IssueVo
|
*/
|
private IssueVo convertToIssueVo(Issue issue) {
|
IssueVo issueVo = ConvertUtil.copyProperties(issue, IssueVo.class);
|
issueVo.setInheritPartners(issue.getIssueType().getInheritPartners());
|
issueVo.setUsePartner(issue.getIssueType().getUsePartner());
|
return issueVo;
|
}
|
|
// 연관이슈를 생성한다.
|
@Override
|
@Transactional
|
public Issue addRelIssue(User user, IssueForm issueForm, List<MultipartFile> 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<Map<String, Object>> 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<String, Object> issueMap = new HashMap<>();
|
// 이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다.
|
this.makeIssueMapToIssue(issue, issueMap);
|
|
Map<String, Object> projectRoleUserMap = new HashMap<>();
|
projectRoleUserMap.put("id", issue.getProject().getId());
|
projectRoleUserMap.put("statuses", Lists.newArrayList("02")); // 관리자 조회
|
// 관리자 정보 셋팅
|
List<Map<String, Object>> projectRoleUsers = this.projectRoleUserService.findProjectRoleUser(projectRoleUserMap);
|
if (projectRoleUsers != null && !projectRoleUsers.isEmpty()) {
|
for (Map<String, Object> 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<String, Object> 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<String, Object> customField = new HashMap<>();
|
|
List<IssueCustomFieldValueVo> issueCustomFieldValueVos = this.issueCustomFieldValueService.findByIssueId(issue.getId());
|
|
for (IssueCustomFieldValueVo issueCustomFieldValueVo : issueCustomFieldValueVos) {
|
// 이미 데이터가 존재
|
if (customField.get(issueCustomFieldValueVo.getCustomFieldVo().getName()) != null) {
|
List<String> useValues = (List<String>) 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<Map<String, Object>> customFields = Lists.newArrayList();
|
|
Iterator<String> iterator = customField.keySet().iterator();
|
while (iterator.hasNext()) {
|
String key = iterator.next();
|
Map<String, Object> 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<AttachedFile> attachedFiles = this.attachedFileService.findByIssueId(issue.getId());
|
|
for (AttachedFile attachedFile : attachedFiles) {
|
attachedFileBuilder.append("<a href='");
|
attachedFileBuilder.append(attachedFile.getPath());
|
attachedFileBuilder.append("'>");
|
attachedFileBuilder.append(attachedFile.getName());
|
attachedFileBuilder.append("</a>");
|
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<Long> myDepartmentIds = Lists.newArrayList();
|
List<UserDepartment> 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<Long> departmentIds = Lists.newArrayList();
|
List<Map<String, Object>> departmentList = this.departmentMapper.find(null);
|
|
if(departmentList != null && departmentList.size() > 0){
|
for(Map<String, Object> department : departmentList){
|
departmentIds.add((Long) department.get("id"));
|
}
|
}
|
issueCondition.setMyDepartmentIds(departmentIds);
|
}
|
|
void SetWorkflowDepartment(List<IssueVo> issueVos){
|
for(IssueVo issueVo : issueVos){
|
Long issueTypeId = issueVo.getIssueTypeId();
|
IssueType issueType = this.issueTypeService.getIssueType(issueTypeId);
|
Long workflowId = issueType.getWorkflow().getId();
|
List<WorkflowDepartment> workflowDepartmentList = this.workflowDepartmentRepository.findByWorkflowId(workflowId);
|
List<Long> 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<IssueVo> findIssue(Map<String, Object> resJsonData, IssueCondition issueCondition, Pageable pageable) {
|
// 검색 조건을 만든다
|
if (!this.makeIssueSearchCondition(issueCondition, Lists.newArrayList("01", "02", "03"), pageable)) {
|
// 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다.
|
this.notFoundIssueList(resJsonData, pageable);
|
return Lists.newArrayList();
|
}
|
|
Set<String> issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션
|
|
// 사용자 정의 필드를 사용한 이슈를 찾는다. 만약 이슈가 없다면 여기서 이슈 조회가 끝난다.
|
if (!this.searchUseCustomFields(issueCondition, issueIds, resJsonData, pageable)) {
|
// 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다.
|
this.notFoundIssueList(resJsonData, pageable);
|
return Lists.newArrayList();
|
}
|
|
List<IssueVo> issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션
|
// 사용자 정의 필드로 검색한 이슈 아이디 값
|
List<String> issueKeys = Lists.newArrayList(issueIds);
|
issueCondition.setIssueIds(issueKeys);
|
User user = this.webAppUtil.getLoginUserObject();
|
|
issueCondition.setLoginUserId(user.getId());
|
issueCondition.setWorkspaceId(user.getLastWorkspaceId());
|
|
|
List<Map<String, Object>> 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<IssueVo> issueVos) {
|
for(IssueVo issueVo : issueVos) {
|
List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueVo.getId());
|
List<IssueVo> 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<IssueVo> issueVos) {
|
for(IssueVo issueVo : issueVos) {
|
List<IssueVo> relationIssues = this.issueRelationService.findRelationIssue(issueVo.getId());
|
for(IssueVo relationIssue : relationIssues){
|
issueVo.addRelationIssueVo(ConvertUtil.copyProperties(relationIssue, IssueVo.class));
|
}
|
}
|
}
|
|
// 상위 이슈 체크
|
private void setParentIssue(List<IssueVo> 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<IssueVo> issueVos) {
|
for (IssueVo issueVo : issueVos){
|
List<Issue> 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<String, Object> resJsonData) {
|
|
IssueTypeCondition issueTypeCondition = new IssueTypeCondition();
|
issueTypeCondition.setIsApi(Issue.IS_API_YES);
|
List<IssueTypeVo> issueTypes = this.issueTypeService.findIssueType(issueTypeCondition);
|
|
// 검색 일자를 구한다.
|
List<Date> 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<ApiMonitorVo> 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<String, Object> data = new HashMap<>();
|
data.put("issueTypeVos", issueTypes);
|
data.put("apiMonitorVos", apiMonitorVos);
|
resJsonData.put(Constants.RES_KEY_CONTENTS, data);
|
}
|
|
|
// 이슈 목록을 조회한다(차트용 - 연관일감포함)
|
@Override
|
@Transactional(readOnly = true)
|
public List<IssueVo> findChartIssue(Map<String, Object> resJsonData,
|
IssueCondition issueCondition, Pageable pageable) {
|
|
// 검색 조건을 만든다
|
if (!this.makeIssueSearchCondition(issueCondition,Lists.newArrayList("01", "02", "03"), pageable)) {
|
// 이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다.
|
this.notFoundIssueList(resJsonData, pageable);
|
return Lists.newArrayList();
|
}
|
|
Set<String> 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<IssueVo> issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션
|
// 사용자 정의 필드로 검색한 이슈 아이디 값
|
List<String> issueKeys = Lists.newArrayList(issueIds);
|
issueCondition.setIssueIds(issueKeys);
|
|
List<Map<String, Object>> 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<IssueVo> findChartIssue(Map<String, Object> 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<String> issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션
|
List<IssueVo> issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션
|
// 사용자 정의 필드로 검색한 이슈 아이디 값
|
List<String> issueKeys = Lists.newArrayList(issueIds);
|
issueCondition.setIssueIds(issueKeys);
|
|
List<Map<String, Object>> 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<Map<String, Object>> results, List<IssueVo> issueVos, IssueCondition issueCondition) {
|
for (Map<String, Object> 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<Map<String, Object>> results, List<IssueVo> issueVos, IssueCondition issueCondition, User user) {
|
for (Map<String, Object> result : results) {
|
IssueVo issueVo = ConvertUtil.convertMapToClass(result, IssueVo.class);
|
if (MapUtil.getString(result, "inheritPartners") != null && MapUtil.getString(result, "inheritPartners").equals("1")) {
|
issueVo.setInheritPartners(true);
|
}
|
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<String> 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<Map<String, Object>> 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<Long> projectIds = Lists.newArrayList();
|
for (Map<String, Object> 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<Map<String, Object>> 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<Long> projectIds = Lists.newArrayList();
|
|
for (Map<String, Object> 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<String, Object> 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<String> issueIds, Map<String, Object> 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<IssueVo> issueVos, IssueCondition issueCondition, User user) {
|
if (issueVos.size() < 1) {
|
return;
|
}
|
|
List<Map<String, Object>> issueUsers = this.issueMapper.findIssueUser(issueCondition);
|
Map<String, Object> issueConverterUsers = new HashMap<>();
|
|
// 이슈에 해당하는 이슈 담당자 정보 셋팅
|
for (Map<String, Object> issueUser : issueUsers) {
|
String issueId = MapUtil.getString(issueUser, "issueId");
|
|
if (MapUtil.getObject(issueConverterUsers, issueId) != null) {
|
List<UserVo> 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<UserVo> 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<UserVo> 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<IssueVo> issueVos, IssueCondition issueCondition, User user) {
|
if (issueVos.size() < 1) {
|
return;
|
}
|
|
List<Map<String, Object>> issueDepartments = this.issueMapper.findIssueDepartment(issueCondition);
|
Map<String, Object> issueConverterDepartments = new HashMap<>();
|
|
// 이슈에 해당하는 이슈 담당부서 정보 셋팅
|
for (Map<String, Object> issueDepartment : issueDepartments) {
|
String issueId = MapUtil.getString(issueDepartment, "issueId");
|
|
if (MapUtil.getObject(issueConverterDepartments, issueId) != null) {
|
List<DepartmentVo> departments = (List) MapUtil.getObject(issueConverterDepartments, issueId);
|
departments.add(new DepartmentVo(MapUtil.getLong(issueDepartment, "id"), MapUtil.getString(issueDepartment, "departmentName"), MapUtil.getString(issueDepartment, "departmentDescription")));
|
} else {
|
List<DepartmentVo> 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<DepartmentVo> 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<String, Object> 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<Issue> downIssues = null;
|
|
List<Issue> 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<IssueVo> 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<UsePartnerVo> 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<IssueVo> 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<IssueRelation> issueRelations = issue.getIssueRelations();
|
|
List<Map<String, Object>> 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<String, Object> 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<IssueCompany> issueCompanies = relationIssue.getIssueCompanies();
|
Iterator<IssueCompany> itrCompany = issueCompanies.iterator();
|
while (itrCompany.hasNext()) {
|
issueRelationVo.addIssueCompanyVo(ConvertUtil.copyProperties(itrCompany.next(), IssueCompanyVo.class));
|
}
|
|
Set<IssueIsp> issueIsps = relationIssue.getIssueIspFields();
|
Iterator<IssueIsp> itrIsp = issueIsps.iterator();
|
while (itrIsp.hasNext()) {
|
issueRelationVo.addIssueIspVo(ConvertUtil.copyProperties(itrIsp.next(), IssueIspVo.class));
|
}
|
|
Set<IssueHosting> issueHostings = relationIssue.getIssueHostingFields();
|
Iterator<IssueHosting> 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<UserVo> 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<DepartmentVo> departmentVos = Lists.newArrayList();
|
|
for (IssueDepartment issueDepartment : issue.getIssueDepartments()) {
|
DepartmentVo departmentVo = ConvertUtil.copyProperties(issueDepartment.getDepartment(), DepartmentVo.class);
|
departmentVo.setByName(departmentVo.getDepartmentName());
|
departmentVos.add(departmentVo);
|
|
List<UserDepartment> 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<AttachedFileVo> 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<IssueTypeCustomFieldVo> issueTypeCustomFieldVos = this.issueTypeCustomFieldService.findIssueTypeCustomField(new HashMap<>(), issueTypeCustomFieldCondition);
|
issueVo.setIssueTypeCustomFieldVos(issueTypeCustomFieldVos);
|
|
// 이슈에서 사용된 사용자 정의 필드 값을 가져온다.
|
List<IssueCustomFieldValueVo> 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<Issue> findIssue(IssueApiForm issueApiform) {
|
|
List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
|
List<Issue> resultIssueVos = Lists.newArrayList();
|
String comma = ",";
|
|
List<String> 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<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
|
if (results != null && results.size() > 0) {
|
for (Map<String, Object> result : results) {
|
resultIssueVos.add(this.getIssue(MapUtil.getLong(result, "id")));
|
}
|
}
|
}
|
|
return resultIssueVos;
|
}
|
|
// 리스트에서 해당 아이디를 가지고 있는 이슈 검색
|
private IssueVo findIssueVo(List<IssueVo> list, Long id) {
|
for (IssueVo issueVo : list) {
|
if (id.equals(issueVo.getId())) {
|
return issueVo;
|
}
|
}
|
return null;
|
}
|
|
|
// 이슈를 수정한다(api용)
|
@Override
|
@Transactional
|
public List<Issue> modifyIssue(IssueApiForm issueApiForm, List<MultipartFile> files) {
|
User user = this.convertToUser(issueApiForm.getToken());
|
IssueForm issueForm = this.convertToIssueForm(issueApiForm, user);
|
|
List<Issue> issue = this.findIssue(issueApiForm);
|
if (issue != null && issue.size() > 0) {
|
List<Issue> 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<IssueTypeApiEndStatus> 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<Map<String, Object>> 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<MultipartFile> 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<MultipartFile> 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<MultipartFile> 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<MultipartFile> 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<Map<String, Object>> 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);
|
|
// 파트너정보 하위이슈 상속
|
List<Issue> downIssues = this.issueRepository.findByParentIssueId(issue.getId());
|
if (issueForm.getInheritYn() != null && issueForm.getInheritYn()
|
&& downIssues != null && downIssues.size() > 0) {
|
for (Issue downIssue : downIssues) {
|
this.inheritPartners(downIssue, issue);
|
}
|
}
|
|
// 이슈 이력 등록
|
if (!StringUtils.isEmpty(detectIssueChange.toString())) {
|
this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString());
|
}
|
|
return issue;
|
}
|
|
// multipartFile 을 file Map 객체로 변경한다.
|
private List<Map<String, Object>> convertMultipartFileToFile(List<MultipartFile> multipartFiles) {
|
List<Map<String, Object>> convertFileMaps = Lists.newArrayList();
|
|
if (multipartFiles != null && multipartFiles.size() > 0) {
|
for (MultipartFile multipartFile : multipartFiles) {
|
try {
|
Map<String, Object> 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<Long> 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<Long> 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<UserVo> getIssueUserVos(Issue issue) {
|
List<UserVo> userVos = Lists.newArrayList();
|
|
Set<IssueUser> 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<DepartmentVo> getIssueDepartmentVos(Issue issue) {
|
List<DepartmentVo> departmentVos = Lists.newArrayList();
|
|
Set<IssueDepartment> 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<UserVo> issueUserVos, User user, List<DepartmentVo> 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<UserVo> issueUserVos, List<DepartmentVo> 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<UserDepartment> 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<String> 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("<ul class=\"activity-list\">");
|
stringBuilder.append(detectIssueChange.toString());
|
stringBuilder.append("</ul>");
|
|
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("<ul class=\"activity-list\">");
|
stringBuilder.append(detectIssueChange.toString());
|
stringBuilder.append("</ul>");
|
|
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("<ul class=\"activity-list\">");
|
stringBuilder.append(detectIssueChange.toString());
|
stringBuilder.append("</ul>");
|
|
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<Issue> removeIssues = Lists.newArrayList();
|
|
for (Long issueId : issueForm.getRemoveIds()) {
|
//하위이슈 체크
|
List<Issue> 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<Issue> removeIssues = Lists.newArrayList();
|
|
for (Long issueId : issueForm.getRemoveIds()) {
|
//하위이슈 체크
|
List<Issue> 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<Issue> removeIssues = Lists.newArrayList();
|
Long downIssueId = 0L;
|
for (Long issueId : issueForm.getRemoveIds()) {
|
//삭제 할 이슈의 하위이슈 체크
|
List<Issue> 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<Long> attachedFileIds = Lists.newArrayList();
|
|
for (AttachedFile attachedFile : issue.getAttachedFiles()) {
|
attachedFileIds.add(attachedFile.getId());
|
}
|
// 첨부파일 삭제
|
this.attachedFileService.removeAttachedFiles(attachedFileIds);
|
}
|
|
// 지울 이슈가 연관이슈인지 체크 후 연관이슈 테이블에서도 삭제한다.
|
List<IssueRelation> 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<Map<String, Object>> issueMaps = this.issueMapper.findByIssueTypeId(issueType.getId());
|
List<IssueStatusVo> issueStatusVos = this.issueStatusService.findByWorkflowId(workflow.getId());
|
IssueStatus readyIssueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(workflow);
|
List<Issue> updateIssues = Lists.newArrayList();
|
|
for (Map<String, Object> 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<String, Object> 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<String> issueIds = new HashSet<>(); // 사용자 정의 필드 검색시 나오는 이슈 아이디 저장 컬렉션
|
Map<String, Object> 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<IssueVo> issueVos = Lists.newArrayList(); // 이슈 목록 데이터 저장 컬렉션
|
// 사용자 정의 필드로 검색한 이슈 아이디 값
|
List<String> issueKeys = Lists.newArrayList(issueIds);
|
issueCondition.setIssueIds(issueKeys);
|
|
List<Map<String, Object>> 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<Map<String, String>> 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<CustomField> 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<IssueVo> issueVos, IssueCondition issueCondition) {
|
// 이슈에서 저장한 사용자 정의 필드 값을 조회한다.
|
List<Map<String, Object>> issueCustomFieldValues = this.issueCustomFieldValueService.findInIssueIds(issueCondition);
|
|
for (IssueVo issueVo : issueVos) {
|
for (Map<String, Object> issueCustomFieldValue : issueCustomFieldValues) {
|
int count = 0;
|
Map<String, Object> useValues = new HashMap<>();
|
|
if (issueVo.getId().equals(MapUtil.getLong(issueCustomFieldValue, "issueId"))) {
|
IssueCustomFieldValueVo issueCustomFieldValueVo = new IssueCustomFieldValueVo();
|
|
useValues.put("useValue"+count, MapUtil.getString(issueCustomFieldValue, "useValue"));
|
useValues.put("customFieldId", MapUtil.getLong(issueCustomFieldValue, "customFieldId"));
|
issueCustomFieldValueVo.setUseValues(useValues);
|
|
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<IssueCompanyVo> 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<IssueIspVo> 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<IssueHostingVo> 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<IssueVo> relationIssues = this.issueRelationService.findRelationIssue(issueId);
|
issueVo.setIssueRelationIssueVos(relationIssues);
|
}
|
|
// IssueVos 데이터를 엑셀에서 표시할 수 있는 데이터로 변경한다.
|
private List<Map<String, String>> convertExcelViewToIssueVos(List<IssueVo> issueVos) {
|
List<Map<String, String>> results = Lists.newArrayList();
|
|
for (IssueVo issueVo : issueVos) {
|
try {
|
Map<String, String> 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<String, Object> 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<String, Object> conditions) {
|
List<IssueTypeCustomField> 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<String, Priority> priorityMaps = new HashMap<>(); // 우선 순위 모음
|
Map<String, Severity> severityMaps = new HashMap<>(); // 중요도 모음
|
Map<String, DepartmentVo> departmentMaps = new HashMap<>(); // 부서 모음
|
Map<String, CustomField> customFieldMaps = new HashMap<>();
|
Map<Long, Long> issueNumberMaps = new HashMap<>(); // 이슈 번호 모음
|
Map<String, Long> issueTypeCustomFieldMaps = new HashMap<>(); // 이슈 타입 + 사용자 정의 필드 연결 정보
|
|
Map<String, CompanyField> companyFieldMaps = new HashMap<>(); //업체 모음
|
Map<String, IspField> ispFieldMaps = new HashMap<>(); //isp 모음
|
Map<String, HostingField> 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<IssueForm> issueForms = Lists.newArrayList();
|
List<String> headers = Lists.newArrayList();
|
|
Workbook workbook;
|
|
IssueType issueType = new IssueType();
|
Workflow workflow = new Workflow();
|
|
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, customFieldMaps,
|
companyFieldMaps, ispFieldMaps, hostingFieldMaps, headers);
|
ConvertUtil.copyProperties(issueForm, newIssueForm);
|
|
Project project = this.projectService.getProject(newIssueForm.getProjectId());
|
Long issueNumber = this.issueNumberGeneratorService.generateIssueNumber(project);
|
newIssueForm.setIssueNumber(issueNumber);
|
|
issueType = this.issueTypeService.getIssueType(newIssueForm.getIssueTypeId());
|
workflow = issueType.getWorkflow();
|
IssueStatus issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(workflow);
|
|
newIssueForm.setIssueStatusId(issueStatus.getId());
|
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);
|
|
if (issueForm.getInheritYn() != null && issueForm.getInheritYn() && issueForm.getParentIssueId() != null) {
|
Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
|
// 상위이슈의 파트너 정보 상속
|
this.inheritPartners(issue, parentIssue);
|
}
|
|
saveIssueForm.setId(issue.getId());
|
|
// 워크플로우 대기 상태의 부서 추가
|
List<Long> departmentsIds = this.workflowDepartmentService.findFirstDepartmentIds(workflow);
|
if (departmentsIds != null && departmentsIds.size() > 0) {
|
this.issueDepartmentService.add(departmentsIds, workspace, issue);
|
}
|
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 등록
|
if (issueForm.getIssueCompanyFields() != null && issueForm.getIssueCompanyFields().size() > 0) {
|
for (Map<String, Object> issueCompanyMap : issueForm.getIssueCompanyFields()) {
|
CompanyField companyField = ConvertUtil.convertMapToClass(issueCompanyMap, CompanyField.class);
|
IssueCompany issueCompany = ConvertUtil.convertMapToClass(issueCompanyMap, IssueCompany.class, "id", "registerDate", "modifyDate");
|
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 issueIsp = ConvertUtil.copyProperties(ispField, IssueIsp.class, "id", "registerDate", "modifyDate");
|
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 issueHosting = ConvertUtil.copyProperties(hostingField, IssueHosting.class, "id", "registerDate", "modifyDate");
|
issueHosting.setHostingField(hostingField);
|
issueHosting.setIssue(issue);
|
this.issueHostingRepository.saveAndFlush(issueHosting);
|
}
|
}
|
}
|
}
|
//issueIsp 등록
|
if (issueForm.getIssueIspFields() != null && issueForm.getIssueIspFields().size() > 0) {
|
for (Map<String, Object> issueIspMap : issueForm.getIssueIspFields()) {
|
IssueIsp issueIsp = ConvertUtil.convertMapToClass(issueIspMap, IssueIsp.class, "id", "registerDate", "modifyDate");
|
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<String, Object> issueHostingMap : issueForm.getIssueHostingFields()) {
|
IssueHosting issueHosting = ConvertUtil.convertMapToClass(issueHostingMap, IssueHosting.class, "id", "registerDate", "modifyDate");
|
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<IssueForm> issueForms) {
|
List<Map<String, Object>> issueHistoryMaps = Lists.newArrayList();
|
|
for (IssueForm issueForm : issueForms) {
|
Map<String, Object> 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<IssueForm> issueForms, Workspace workspace) {
|
List<Map<String, Long>> issueAssigneeMaps = Lists.newArrayList();
|
|
for (IssueForm issueForm : issueForms) {
|
for (Long departmentId : issueForm.getDepartmentIds()) {
|
Map<String, Long> 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<IssueForm> issueForms, Workspace workspace) {
|
List<Map<String, Long>> issueRiskMaps = Lists.newArrayList();
|
for (IssueForm issueForm : issueForms) {
|
Map<String, Long> 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<IssueForm> issueForms, Map<String, Long> issueTypeCustomFieldMaps) {
|
List<Map<String, Object>> issueCustomFieldValueMaps = Lists.newArrayList();
|
|
for (IssueForm issueForm : issueForms) {
|
for (Map<String, Object> 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);
|
}
|
|
// 엑셀에 업체명을 입력하지 않았을 경우 같은 도메인 업체 찾기
|
this.findPartnerByDomain(issueForm);
|
}
|
|
if (issueCustomFieldValueMaps.size() > 0) {
|
this.issueMapper.insertIssueCustomFieldValueBatch(issueCustomFieldValueMaps);
|
}
|
}
|
|
/**
|
* 엑셀에 업체명을 입력하지 않았을 경우 같은 도메인 업체 찾기
|
* @param issueForm IssueForm
|
*/
|
private void findPartnerByDomain(IssueForm issueForm) {
|
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<String, Object> 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<String, Object> 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<String, Object> 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);
|
}
|
}
|
}
|
}
|
|
// 이슈의 주요 속성을 map 에 저장하여 엑셀 import 에서 지정한 대상(이슈 속성)을 빠르게 찾을 수 있게 한다.
|
private void IssueAttributeMapToList(IssueForm issueForm, Map<String, Priority> priorityMaps, Map<String, Severity> severityMaps,
|
Map<String, DepartmentVo> departmentMaps, Map<String, CustomField> customFieldMaps,Map<String, Long> issueTypeCustomFieldMaps,
|
Map<String, CompanyField> companyFieldMaps, Map<String, IspField> ispFieldMaps, Map<String, HostingField> 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<Priority> priorities = this.priorityService.findByWorkspaceId();
|
for (Priority priority : priorities) {
|
priorityMaps.put(priority.getName(), priority);
|
}
|
|
// 중요도를 바로 찾을 수 있게 준비
|
List<Severity> severities = this.severityService.findByWorkspaceId();
|
for (Severity severity : severities) {
|
severityMaps.put(severity.getName(), severity);
|
}
|
|
// 사용자 정의 필드를 바로 찾을 수 있게 준비
|
List<CustomField> customFields = this.customFieldService.findByWorkspaceId();
|
for (CustomField customField : customFields) {
|
customFieldMaps.put(customField.getName(), customField);
|
}
|
|
// 업체 정보를 바로 찾을 수 있게 준비
|
List<CompanyField> companyFields = this.companyFieldService.findAll();
|
for (CompanyField companyField : companyFields) {
|
companyFieldMaps.put(companyField.getName(), companyField);
|
}
|
// ISP 정보를 바로 찾을 수 있게 준비
|
List<IspField> ispFields = this.ispFieldService.findAll();
|
for (IspField ispField : ispFields) {
|
ispFieldMaps.put(ispField.getName(), ispField);
|
}
|
// 호스팅 정보를 바로 찾을 수 있게 준비
|
List<HostingField> hostingFields = this.hostingFieldService.findAll();
|
for (HostingField hostingField : hostingFields) {
|
hostingFieldMaps.put(hostingField.getName(), hostingField);
|
}
|
}
|
|
/**
|
* cell String으로 변환 함수
|
* @param cell Cell
|
* @param isNull boolean
|
* @return String
|
*/
|
private String stringToCell (Cell cell, boolean isNull) {
|
String cellStr = "";
|
if (!isNull) {
|
cellStr = CommonUtil.convertExcelStringToCell(cell);
|
// 공백 제거
|
cell.setCellValue(cellStr.trim());
|
} else {
|
cell.setCellValue(cellStr);
|
}
|
return cellStr;
|
}
|
|
/**
|
* cell NULL 체크 함수
|
* 빈 값이 아닌 cell 체크
|
* @param cell Cell
|
* @return boolean
|
*/
|
private Boolean cellNullCheck (Cell cell) {
|
int cellType = cell.getCellType();
|
if (cellType < Cell.CELL_TYPE_BLANK) {
|
if (cellType == Cell.CELL_TYPE_STRING) {
|
if (cell.getStringCellValue() != null && !cell.getStringCellValue().equals("")) {
|
return false;
|
}
|
} else {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
// 엑셀 필드에 있는 정보를 이슈 form 으로 옮긴다.
|
private IssueForm setIssueFormToExcelField(Row row, int rowIndex, Map<String, Priority> priorityMaps,
|
Map<String, Severity> severityMaps, Map<String, CustomField> customFieldMaps,
|
Map<String, CompanyField> companyFieldMaps, Map<String, IspField> ispFieldMaps, Map<String, HostingField> hostingFieldMaps,
|
List<String> headers) throws ParseException {
|
IssueForm issueForm = new IssueForm();
|
issueForm.setRegisterId(this.webAppUtil.getLoginId());
|
|
// 제목, 내용, 프로젝트 키, 이슈 타입, 우선순위, 중요도, 담당자, 시작일, 종료일, 사용자 정의 필드
|
for (int cellIndex = 0; cellIndex < headers.size(); cellIndex++) {
|
Cell cell = row.getCell(cellIndex);
|
|
String cellStr = "";
|
boolean isNull = true;
|
|
if (cell != null) {
|
isNull = cellNullCheck(cell);
|
cellStr = stringToCell(cell, isNull); //cell을 String으로 변환
|
}
|
|
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<String, HostingField> hostingFieldMaps, IssueForm issueForm, int rowIndex) {
|
if (cell.length() > 0) {
|
Map<String, Object> 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<String, IspField> ispFieldMaps, IssueForm issueForm, int rowIndex) {
|
if (cell.length() > 0) {
|
Map<String, Object> 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<String, CompanyField> companyFieldMaps, IssueForm issueForm, int rowIndex) {
|
if (cell.length() > 0) {
|
Map<String, Object> 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<String, Project> 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<Long, Long> 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<String, Priority> 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<String, Severity> 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<String, Object> userMaps, IssueForm issueForm, Project project) {
|
if (cell != null) {
|
String[] splitAssignee = CommonUtil.convertExcelStringToCell(cell).split("#");
|
Map<String, Object> userMap = (Map<String, Object>) MapUtil.getObject(userMaps, project.getProjectKey());
|
|
List<Long> 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(DateUtil.convertDateToStr(startDate, "yyyy-MM-dd"));
|
} else {
|
issueForm.setCompleteDate(DateUtil.convertDateToStr(startDate, "yyyy-MM-dd"));
|
|
// 종료일만 입력 했을 경우
|
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_VALID, rowIndex));
|
}
|
}
|
}
|
}
|
|
// 사용자 정의 필드 정보를 IssueForm 에 저장한다.-
|
private void setIssueFormCustomFieldValue(String cellValue, Map<String, CustomField> customFieldMaps, IssueForm issueForm, String customFieldName, int rowIndex) {
|
Map<String, Object> 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));
|
}
|
|
//DATETIME일 경우 format 변경
|
if (customField.getCustomFieldType() == DATETIME) {
|
Date date = DateUtil.convertStrToDate(cellValue);
|
if (date == null) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_DATETIME_NOT_DASH, rowIndex));
|
}
|
}
|
|
//IP_ADDRESS일 경우 정규표현식 체크
|
if (customField.getCustomFieldType() == IP_ADDRESS) {
|
String regExp = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
|
+ "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
|
+ "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
|
+ "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
|
if (!cellValue.matches(regExp)) {
|
throw new OwlRuntimeException(
|
this.messageAccessor.getMessage(MsgConstants.EXCEL_IMPORT_IP_ADDRESS_NOT_VALIDITY, 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<String, Object> 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<Long> findByProjectId(Long projectId) {
|
List<Map<String, Object>> issueMaps = this.issueMapper.findByProjectId(projectId);
|
List<Long> issueIds = Lists.newArrayList();
|
|
for (Map<String, Object> 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<String, Object> 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<MultipartFile> 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<MultipartFile> 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<IssueReservation> 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<String, Object> findTask(IssueCondition taskCondition) {
|
|
StopWatch serviceStart = new StopWatch();
|
serviceStart.start();
|
ProjectCondition projectCondition = new ProjectCondition(this.webAppUtil.getLoginUser().getLastProjectId(), this.webAppUtil.getLoginId());
|
List<Map<String, Object>> 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<Map<String, Object>> results = this.taskMapper.find(taskCondition);
|
List<Map<String, Object>> results = this.issueMapper.find(taskCondition);
|
|
serviceStart.stop();
|
long executeTime = serviceStart.getTime();
|
|
Map<String, Object> tasks = new HashMap<>();
|
// 워크플로우 상태 id 를 키로 만든다.
|
for (Long workflowStatusId : taskCondition.getStatusIds()) {
|
tasks.put(workflowStatusId.toString(), Lists.newArrayList());
|
}
|
|
Map<String, Object> taskUserSave = new HashMap<>();
|
// 전체 task_id를 모은다.
|
for (Map<String, Object> result : results) {
|
Long taskId = MapUtil.getLong(result, "id");
|
taskCondition.addIssueIds(taskId.toString());
|
// 각 task_id 별로 사용자 정보를 저장할 공간을 미리 확보한다.
|
taskUserSave.put(taskId.toString(), Lists.newArrayList());
|
}
|
|
List<Map<String, Object>> taskDepartments = Lists.newArrayList();
|
// task 가 하나도 없을 경우에는 조회를 하지 않는다.
|
if (!taskCondition.getIssueIds().isEmpty()) {
|
//taskUsers = this.issueMapper.getAllTaskUser(taskCondition);
|
taskDepartments = this.issueMapper.getAllTaskUser(taskCondition);
|
}
|
|
// task_id 에 매칭되는 담당자 정보를 준비한다.
|
/*for (Map<String, Object> taskUser : taskUsers) {
|
Long taskId = MapUtil.getLong(taskUser, "taskId");
|
List<UserVo> userVos = (List<UserVo>)taskUserSave.get(taskId.toString());
|
userVos.add(ConvertUtil.convertMapToClass(taskUser, UserVo.class));
|
}*/
|
|
for (Map<String, Object> taskDepartment : taskDepartments) {
|
Long taskId = MapUtil.getLong(taskDepartment, "taskId");
|
List<DepartmentVo> departmentVos = (List<DepartmentVo>)taskUserSave.get(taskId.toString());
|
departmentVos.add(ConvertUtil.convertMapToClass(taskDepartment, DepartmentVo.class));
|
}
|
|
for (Map<String, Object> 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<UserVo> userVos = (List<UserVo>)taskUserSave.get(taskVo.getId().toString());
|
//taskVo.setUserVos(userVos);
|
|
// 담당부서 세팅
|
List<DepartmentVo> departmentVos = (List<DepartmentVo>)taskUserSave.get(taskVo.getId().toString());
|
taskVo.setDepartmentVos(departmentVos);
|
|
List<IssueVo> taskVos = (List<IssueVo>)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);
|
}
|
|
if (issueDownForm.getInheritYn() != null && issueDownForm.getInheritYn() && issue.getParentIssue() != null) {
|
// 상위이슈의 파트너 정보 상속받기
|
issue = this.inheritPartners(issue, parentIssue);
|
}
|
|
this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); //parentIssue = myIssue(기록은 현재 상세페이지에 해야하니까)
|
this.issueRepository.saveAndFlush(issue);
|
}
|
}
|
|
/**
|
* 상위이슈의 파트너 정보 상속받기
|
* @param issue Issue
|
* @param parentIssue Issue
|
* @return Issue
|
*/
|
private Issue inheritPartners(Issue issue, Issue parentIssue) {
|
if (parentIssue != null) {
|
if (parentIssue.getIssueType().getInheritPartners()) {
|
IssueCompany issueCompany = new IssueCompany();
|
IssueIsp issueIsp = new IssueIsp();
|
IssueHosting issueHosting = new IssueHosting();
|
|
if (parentIssue.getIssueCompanies() != null && parentIssue.getIssueCompanies().size() > 0) {
|
issue.getIssueCompanies().clear();
|
issue.getIssueCompanies().addAll(parentIssue.getIssueCompanies());
|
Iterator<IssueCompany> itrCompany = issue.getIssueCompanies().iterator();
|
ConvertUtil.copyProperties(itrCompany.next(), issueCompany, "id");
|
issueCompany.setIssue(issue);
|
issueCompany.setCompanyField(parentIssue.getIssueCompanies().iterator().next().getCompanyField());
|
this.issueCompanyRepository.saveAndFlush(issueCompany);
|
} else {
|
this.issueCompanyRepository.deleteByIssueId(issue.getId());
|
this.issueCompanyRepository.flush();
|
}
|
if (parentIssue.getIssueIspFields() != null && parentIssue.getIssueIspFields().size() > 0) {
|
issue.getIssueIspFields().clear();
|
issue.getIssueIspFields().addAll(parentIssue.getIssueIspFields());
|
Iterator<IssueIsp> itrIsp = issue.getIssueIspFields().iterator();
|
ConvertUtil.copyProperties(itrIsp.next(), issueIsp, "id");
|
issueIsp.setIssue(issue);
|
issueIsp.setIspField(parentIssue.getIssueIspFields().iterator().next().getIspField());
|
this.issueIspRepository.saveAndFlush(issueIsp);
|
} else {
|
this.issueIspRepository.deleteByIssueId(issue.getId());
|
this.issueIspRepository.flush();
|
}
|
if (parentIssue.getIssueHostingFields() != null && parentIssue.getIssueHostingFields().size() > 0) {
|
issue.getIssueHostingFields().clear();
|
issue.getIssueHostingFields().addAll(parentIssue.getIssueHostingFields());
|
Iterator<IssueHosting> itrHosting = issue.getIssueHostingFields().iterator();
|
ConvertUtil.copyProperties(itrHosting.next(), issueHosting, "id");
|
issueHosting.setIssue(issue);
|
issueHosting.setHostingField(parentIssue.getIssueHostingFields().iterator().next().getHostingField());
|
this.issueHostingRepository.saveAndFlush(issueHosting);
|
} else {
|
this.issueHostingRepository.deleteByIssueId(issue.getId());
|
this.issueHostingRepository.flush();
|
}
|
}
|
}
|
return issue;
|
}
|
|
@Override
|
public void findPartner(Map<String, Object> resJsonData, Map<String, Object> params) {
|
Long issueTypeId = MapUtil.getLong(params, "issueTypeId");
|
List<UsePartnerVo> 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<String, Object> 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<Map<String, Object>> departmentVos = this.departmentMapper.findByIssueStatusId(condition);
|
resJsonData.put(Constants.RES_KEY_CONTENTS, departmentVos);
|
}
|
}
|