package kr.wisestone.owl.service.impl;
|
|
import com.google.common.collect.Lists;
|
import kr.wisestone.owl.domain.*;
|
import kr.wisestone.owl.domain.enumType.CustomFieldType;
|
import kr.wisestone.owl.domain.enumType.IssueHistoryType;
|
import kr.wisestone.owl.mapper.IssueCustomFieldValueMapper;
|
import kr.wisestone.owl.repository.IssueCustomFieldValueRepository;
|
import kr.wisestone.owl.service.*;
|
import kr.wisestone.owl.util.ConvertUtil;
|
import kr.wisestone.owl.util.MapUtil;
|
import kr.wisestone.owl.vo.CustomFieldVo;
|
import kr.wisestone.owl.vo.IssueCustomFieldValueVo;
|
import kr.wisestone.owl.web.condition.IssueCondition;
|
import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import java.util.*;
|
|
@Service
|
public class IssueCustomFieldValueServiceImpl extends AbstractServiceImpl<IssueCustomFieldValue, Long, JpaRepository<IssueCustomFieldValue, Long>> implements IssueCustomFieldValueService {
|
|
private static final Logger log = LoggerFactory.getLogger(IssueCustomFieldValueServiceImpl.class);
|
|
@Autowired
|
private IssueCustomFieldValueRepository issueCustomFieldValueRepository;
|
|
@Autowired
|
private CustomFieldService customFieldService;
|
|
@Autowired
|
private IssueHistoryService issueHistoryService;
|
|
@Autowired
|
private IssueCustomFieldValueMapper issueCustomFieldValueMapper;
|
|
@Autowired
|
private IssueTypeCustomFieldService issueTypeCustomFieldService;
|
|
@Autowired
|
private UserService userService;
|
|
@Override
|
protected JpaRepository<IssueCustomFieldValue, Long> getRepository() {
|
return this.issueCustomFieldValueRepository;
|
}
|
|
// 이슈에서 사용되는 사용자 정의 필드 값을 업데이트한다.
|
@Override
|
@Transactional
|
public void modifyIssueCustomFieldValue(Issue issue, List<Map<String, Object>> issueCustomFields) {
|
// 전체 이슈에 사용되는 사용자 정의 필드 값 삭제
|
issue.getIssueCustomFieldValues().clear();
|
List<IssueCustomFieldValue> issueCustomFieldValues = Lists.newArrayList();
|
|
for (Map<String, Object> map : issueCustomFields) {
|
Map<String, Object> result = new HashMap<>();
|
// customFieldVo 에서 사용자 정의 필드와 이슈 유형에 연결된 사용자 정의 필드 정보를 가져온다.
|
this.getCustomFieldAndIssueTypeCustomField(map, issue, result);
|
List<String> useValues = MapUtil.getStrings(map, "useValues");
|
|
if (useValues != null) {
|
for (String useValue : useValues) {
|
if (!StringUtils.isEmpty(useValue)) {
|
// Xss 공격 방어를 위해 script 공백으로 치환
|
IssueCustomFieldValue issueCustomFieldValue = new IssueCustomFieldValue(issue, (CustomField)result.get("customField"), (IssueTypeCustomField)result.get("issueTypeCustomField"), useValue);
|
issueCustomFieldValues.add(issueCustomFieldValue);
|
}
|
}
|
}
|
}
|
|
if (issueCustomFieldValues.size() > 0) {
|
this.issueCustomFieldValueRepository.saveAll(issueCustomFieldValues);
|
}
|
}
|
|
// customFieldVo 에서 사용자 정의 필드와 이슈 유형에 연결된 사용자 정의 필드 정보를 가져온다.
|
@Override
|
public void getCustomFieldAndIssueTypeCustomField(Map<String, Object> map, Issue issue, Map<String, Object> result) {
|
Map<String, Object> customFieldMap = (Map<String, Object>) MapUtil.getObject(map, "customFieldVo");
|
CustomField customField = this.customFieldService.getCustomField(MapUtil.getLong(customFieldMap, "id"));
|
IssueTypeCustomField issueTypeCustomField = this.issueTypeCustomFieldService.findByProjectIdAndIssueTypeIdAndCustomFieldId(issue.getProject().getId(), issue.getIssueType().getId(), customField.getId());
|
|
result.put("customField", customField);
|
result.put("issueTypeCustomField", issueTypeCustomField);
|
}
|
|
// 이슈에 연결된 사용자 정의 필드 값을 조회한다.
|
@Override
|
@Transactional(readOnly = true)
|
public List<IssueCustomFieldValueVo> findByIssueId(Long issueId) {
|
List<IssueCustomFieldValueVo> issueCustomFieldValueVos = Lists.newArrayList();
|
List<IssueCustomFieldValue> issueCustomFieldValues = this.issueCustomFieldValueRepository.findByIssueId(issueId);
|
|
for (IssueCustomFieldValue issueCustomFieldValue : issueCustomFieldValues) {
|
IssueCustomFieldValueVo issueCustomFieldValueVo = ConvertUtil.copyProperties(issueCustomFieldValue, IssueCustomFieldValueVo.class);
|
CustomFieldVo customFieldVo = ConvertUtil.copyProperties(issueCustomFieldValue.getCustomField(), CustomFieldVo.class);
|
customFieldVo.setCustomFieldType(issueCustomFieldValue.getCustomField().getCustomFieldType().toString());
|
issueCustomFieldValueVo.setCustomFieldVo(customFieldVo);
|
issueCustomFieldValueVos.add(issueCustomFieldValueVo);
|
}
|
|
return issueCustomFieldValueVos;
|
}
|
|
// 사용자 정의 필드 옵션 값이 변경되었을 때 사용자 정의 필드 값을 사용하는 이슈에서 해당 값이 존재하는지 확인하고 없어졌으면 삭제해준다.
|
@Override
|
@Transactional
|
public void checkExistIssueCustomFieldValue(CustomField customField, List<String> values, CustomFieldType oldCustomFieldType) {
|
|
List<IssueCustomFieldValue> removeIssueCustomFieldValues = Lists.newArrayList();
|
Map<String, Object> issueMaps = new HashMap<>(); // 이력을 남길 이슈 추출
|
|
// 이슈에서 사용되는 사용자 정의 필드 값 정보를 추출한다.
|
this.saveOriginalIssueCustomFieldValues(customField, values, issueMaps, removeIssueCustomFieldValues);
|
|
// 삭제할 값 삭제
|
if (removeIssueCustomFieldValues.size() > 0) {
|
this.issueCustomFieldValueRepository.deleteInBatch(removeIssueCustomFieldValues);
|
// 삭제 후 남은 이슈 사용자 정의 필드 값 정보를 issueMaps 에 저장한다.
|
this.saveNewIssueCustomFieldValues(customField, issueMaps);
|
// 변경된 이슈 사용자 정의 필드 값 정보를 히스토리로 남긴다.
|
this.saveIssueCustomFieldValueHistory(issueMaps, customField, oldCustomFieldType);
|
}
|
}
|
|
// 이슈에서 사용되는 사용자 정의 필드 값 정보를 추출한다.
|
private void saveOriginalIssueCustomFieldValues(CustomField customField, List<String> values, Map<String, Object> issueMaps, List<IssueCustomFieldValue> removeIssueCustomFieldValues) {
|
// 해당 사용자 정의 필드를 사용하고 있는 이슈 정보를 추출한다.
|
List<IssueCustomFieldValue> issueCustomFieldValues = this.findByCustomFieldId(customField);
|
|
// 각 이슈의 이전 값 추출
|
for (IssueCustomFieldValue issueCustomFieldValue : issueCustomFieldValues) {
|
Boolean existValue = false;
|
|
for (String value : values) {
|
if (issueCustomFieldValue.getUseValue().equals(value)) {
|
existValue = true;
|
break;
|
}
|
}
|
|
if (!existValue) {
|
// 삭제할 값
|
removeIssueCustomFieldValues.add(issueCustomFieldValue);
|
}
|
|
String issueId = issueCustomFieldValue.getIssue().getId().toString();
|
|
if (MapUtil.getObject(issueMaps, issueId) == null) {
|
Map<String, Object> issue = new HashMap<>();
|
issue.put("issue", issueCustomFieldValue.getIssue());
|
issue.put("oldValues", Lists.newArrayList(issueCustomFieldValue.getUseValue()));
|
issue.put("newValues", Lists.newArrayList());
|
|
issueMaps.put(issueId, issue);
|
}
|
else {
|
Map<String, Object> issue = (Map<String, Object>) issueMaps.get(issueId);
|
List<String> oldValues = (List<String>) MapUtil.getObject(issue, "oldValues");
|
oldValues.add(issueCustomFieldValue.getUseValue());
|
issue.put("oldValues", oldValues);
|
}
|
}
|
}
|
|
// 삭제 후 남은 이슈 사용자 정의 필드 값 정보를 issueMaps 에 저장한다.
|
private void saveNewIssueCustomFieldValues(CustomField customField, Map<String, Object> issueMaps) {
|
// 삭제 후 다시 이슈 사용자 정의 필드 값을 조회한다.
|
List<IssueCustomFieldValue> newIssueCustomFieldValues = this.findByCustomFieldId(customField);
|
|
for (IssueCustomFieldValue newIssueCustomFieldValue : newIssueCustomFieldValues) {
|
String issueId = newIssueCustomFieldValue.getIssue().getId().toString();
|
|
if (MapUtil.getObject(issueMaps, issueId) != null) {
|
Map<String, Object> issue = (Map<String, Object>) issueMaps.get(issueId);
|
List<String> newValues = (List<String>) MapUtil.getObject(issue, "newValues");
|
newValues.add(newIssueCustomFieldValue.getUseValue());
|
issue.put("newValues", newValues);
|
}
|
}
|
}
|
|
// 변경된 이슈 사용자 정의 필드 값 정보를 히스토리로 남긴다.
|
private void saveIssueCustomFieldValueHistory(Map<String, Object> issueMaps, CustomField customField, CustomFieldType oldCustomFieldType) {
|
Iterator<String> iterator = issueMaps.keySet().iterator();
|
|
while (iterator.hasNext()) {
|
StringBuilder issueChangeDescription = new StringBuilder();
|
Map<String, Object> issueMap = (Map<String, Object>) issueMaps.get(iterator.next());
|
Issue issue = (Issue) MapUtil.getObject(issueMap, "issue");
|
List<String> oldValues = (List<String>) MapUtil.getObject(issueMap, "oldValues");
|
List<String> newValues = (List<String>) MapUtil.getObject(issueMap, "newValues");
|
|
// 배열에 있는 값을 보기 좋게 추출한다.
|
StringBuilder oldValueString = this.setValueString(oldValues);
|
StringBuilder newValueString = this.setValueString(newValues);
|
|
// 이슈 사용자 정의 필드 값이 변경되었는지 확인한다.
|
if (this.checkChangeIssueCustomFieldValues(oldValueString, newValueString)) {
|
continue;
|
}
|
|
// 값이 비었을 때 값이 없다는 글자를 남겨준다.
|
this.setEmptyString(oldValueString, oldCustomFieldType);
|
// 값이 비었을 때 값이 없다는 글자를 남겨준다.
|
this.setEmptyString(newValueString, oldCustomFieldType);
|
|
// 이전에 문자열필드였다가 다른 필드로 변경한 경우나 이전에 문자열 필드가 아니었다가 문자열 필드로 바뀐 경우
|
if (CustomFieldType.INPUT.equals(oldCustomFieldType) && !customField.getCustomFieldType().equals(CustomFieldType.INPUT) ||
|
!CustomFieldType.INPUT.equals(oldCustomFieldType) && customField.getCustomFieldType().equals(CustomFieldType.INPUT)) {
|
// 사용자 정의 필드 유형이 변경되어 이슈에서 사용된 옵션 값이 삭제되었다고 저장한다.
|
this.issueHistoryService.recodeChangeCustomFieldType(customField, oldValueString.toString(), issueChangeDescription);
|
}
|
else {
|
// 사용자 정의 필드의 옵션 값이 삭제되어 이슈에서 사용된 값이 삭제될 경우 변경 정보를 저장한다.
|
this.issueHistoryService.recodeRemoveCustomFieldOptionValue(customField, oldValueString.toString(), newValueString.toString(), issueChangeDescription);
|
}
|
|
this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, issueChangeDescription.toString());
|
}
|
}
|
|
// 배열에 있는 값을 보기 좋게 추출한다.
|
private StringBuilder setValueString(List<String> values) {
|
StringBuilder stringBuilder = new StringBuilder();
|
for (String value : values) {
|
stringBuilder.append(value);
|
stringBuilder.append(", ");
|
}
|
|
return stringBuilder;
|
}
|
|
// 값이 비었을 때 값이 없다는 글자를 남겨준다.
|
private void setEmptyString(StringBuilder stringBuilder, CustomFieldType customFieldType) {
|
if (stringBuilder.toString().equals("")) {
|
if (CustomFieldType.INPUT.equals(customFieldType)) {
|
stringBuilder.append("<span translate=\"common.noValueEntered\">입력한 값이 없습니다.</span>");
|
}
|
else {
|
stringBuilder.append("<span translate=\"common.noValueSelected\">선택한 값이 없습니다.</span>");
|
}
|
}
|
}
|
|
// 이슈 사용자 정의 필드 값이 변경되었는지 확인한다.
|
private boolean checkChangeIssueCustomFieldValues(StringBuilder oldValueString, StringBuilder newValueString) {
|
if (oldValueString.toString().equals(newValueString.toString())) {
|
return true;
|
}
|
|
return false;
|
}
|
|
// 사용자 정의 필드를 사용하고 있는 값 정보를 추출한다.
|
@Override
|
@Transactional(readOnly = true)
|
public List<IssueCustomFieldValue> findByCustomFieldId(CustomField customField) {
|
return this.issueCustomFieldValueRepository.findByCustomFieldId(customField.getId());
|
}
|
|
// 프로젝트에 사용자 정의 필드 연결이 해제될 경우 삭제한다.
|
@Override
|
@Transactional
|
public void removeIssueCustomFieldValue(Long issueTypeCustomFieldId) {
|
this.issueCustomFieldValueMapper.deleteIssueCustomFieldValue(issueTypeCustomFieldId);
|
}
|
|
// 사용자 정의 필드 값을 저장한 이슈를 찾는다.
|
@Override
|
@Transactional(readOnly = true)
|
public boolean find(IssueCondition condition, Set<String> issueIds) {
|
boolean customFieldSearch = false;
|
int firstCount = 0;
|
|
Set<String> tempIssueIds = new HashSet<>();
|
|
for (Map<String, Object> customField : condition.getIssueCustomFields()) {
|
IssueCustomFieldValueCondition issueCustomFieldValueCondition = IssueCustomFieldValueCondition.make(customField);
|
|
if (issueCustomFieldValueCondition.getUseValues().size() > 0 || !StringUtils.isEmpty(issueCustomFieldValueCondition.getUseValue())) {
|
issueCustomFieldValueCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
|
issueCustomFieldValueCondition.setCustomFieldId(MapUtil.getLong(customField, "id"));
|
|
// 사용자 정의 필드 값 검색 시작
|
customFieldSearch = true;
|
Map<String, Object> result = new HashMap<>();
|
|
switch (CustomFieldType.valueOf(issueCustomFieldValueCondition.getCustomFieldType())) {
|
case INPUT:
|
result = this.issueCustomFieldValueMapper.findLikeUseValue(issueCustomFieldValueCondition);
|
break;
|
case MULTI_SELECT:
|
case SINGLE_SELECT:
|
result = this.issueCustomFieldValueMapper.findByUseValue(issueCustomFieldValueCondition);
|
break;
|
}
|
|
String issueIdList = MapUtil.getString(result, "issueIds");
|
|
if (!StringUtils.isEmpty(issueIdList)) {
|
Set<String> results = new HashSet<>(Arrays.asList(issueIdList.split(",")));
|
|
if (firstCount > 0) {
|
Set<String> commonKeys = new HashSet<>(tempIssueIds);
|
commonKeys.retainAll(results);
|
tempIssueIds = commonKeys;
|
}
|
else {
|
tempIssueIds = results;
|
}
|
}
|
|
firstCount++;
|
}
|
}
|
|
issueIds.addAll(tempIssueIds);
|
|
return customFieldSearch;
|
}
|
|
// 이슈에서 저장한 사용자 정의 필드 값을 조회한다.
|
@Override
|
@Transactional(readOnly = true)
|
public List<Map<String, Object>> findInIssueIds(IssueCondition issueCondition) {
|
return this.issueCustomFieldValueMapper.findInIssueIds(issueCondition);
|
}
|
|
// 이슈에서 저장된 해당 사용자 정의 필드 값을 모두 삭제한다.
|
@Override
|
@Transactional
|
public void removeIssueCustomFieldValuesByCustomFieldId(CustomField customField) {
|
// 사용자 정의 필드를 사용하고 있는 값 정보를 추출한다.
|
List<IssueCustomFieldValue> issueCustomFieldValues = this.findByCustomFieldId(customField);
|
List<Long> ids = Lists.newArrayList();
|
|
for (IssueCustomFieldValue issueCustomFieldValue : issueCustomFieldValues) {
|
ids.add(issueCustomFieldValue.getId());
|
}
|
|
if (ids.size() > 0) {
|
this.issueCustomFieldValueMapper.deleteByIssueCustomFieldValueId(ids);
|
}
|
}
|
|
|
}
|