src/main/java/kr/wisestone/owl/constant/MsgConstants.java
@@ -233,5 +233,6 @@ public static final String API_PARAMETER_ISSUE_TYPE_ERROR = "API_PARAMETER_ISSUE_TYPE_ERROR"; // api 파라미터 오류(이슈타입) public static final String API_PARAMETER_PROJECT_ERROR = "API_PARAMETER_PROJECT_ERROR"; // api 파라미터 오류(프로젝트) public static final String API_PARAMETER_ERROR = "API_PARAMETER_ERROR"; // api 파라미터 오류 public static final String API_USER_ERROR = "API_USER_ERROR"; // api 사용자 오류 } src/main/java/kr/wisestone/owl/domain/Issue.java
@@ -340,11 +340,11 @@ this.parentIssue = parentIssue; } public String isApi() { public String getIsApi() { return isApi; } public void setApi(String api) { isApi = api; public void setIsApi(String isApi) { this.isApi = isApi; } } src/main/java/kr/wisestone/owl/service/IssueService.java
@@ -28,7 +28,7 @@ Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles); Issue addApiIssue(IssueApiForm issueApiForm); Issue modifyIssue(IssueApiForm issueApiForm, List<MultipartFile> files); List<IssueVo> findIssue(Map<String, Object> resJsonData, IssueCondition condition, Pageable pageable); @@ -43,6 +43,8 @@ Issue modifyIssue(IssueForm issueForm, List<MultipartFile> files); Issue modifyIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles); void removeIssues(IssueForm issueForm); void modifyIssueStatus(IssueForm issueForm); src/main/java/kr/wisestone/owl/service/impl/ApiTokenServiceImpl.java
@@ -95,7 +95,12 @@ ObjectMapper objectMapper = new ObjectMapper(); //반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용 return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class); try { return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class); } catch (Exception ex) { log.debug(ex.getMessage()); } return null; } private Jws<Claims> decryption(String jwt) { src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -188,11 +188,7 @@ } // API 를 통해 이슈 추가. @Override @Transactional public Issue addApiIssue(IssueApiForm issueApiForm) { private IssueForm convertToIssueForm(IssueApiForm issueApiForm, User user) { if (issueApiForm.getIssueTypeId() == null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR)); } @@ -211,14 +207,7 @@ } issueForm.setProjectId(project.getId()); // 토큰으로 유저 정보 가져오기 String token = issueApiForm.getToken(); UserVo userVo = this.apiTokenService.certification(token); // 해당 유저 정보가 현재 db에 있는지 확인 User user = this.userService.getUser(userVo.getId()); if (user != null) { // 기본값 입력하기 IssueApiDefaultForm issueApiDefaultForm = new IssueApiDefaultForm(); issueApiDefaultForm.setUserId(user.getId()); @@ -226,6 +215,7 @@ 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()); } @@ -248,11 +238,33 @@ // api 입력값 적용 ConvertUtil.copyProperties(issueApiForm, issueForm); return addIssue(user, issueForm, issueApiForm.getMultipartFiles()); return issueForm; } else { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR)); } } private User convertToUser(String token) { // 토큰으로 유저 정보 가져오기 UserVo userVo = this.apiTokenService.certification(token); // 해당 유저 정보가 현재 db에 있는지 확인 return this.userService.getUser(userVo.getId()); } // API 를 통해 이슈 추가. @Override @Transactional public Issue addApiIssue(IssueApiForm issueApiForm) { User user = convertToUser(issueApiForm.getToken()); IssueForm issueForm = this.convertToIssueForm(issueApiForm, user); return addIssue(user, issueForm, issueApiForm.getMultipartFiles()); } // 중복된 상위 이슈 검색 private IssueVo findIssue(IssueApiForm issueApiForm, Long userId) { @@ -316,6 +328,10 @@ 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)); // 각 프로젝트의 고유 이슈 번호 생성 @@ -1209,12 +1225,29 @@ issueVo.setIssueHistoryVos(this.issueHistoryService.findIssueHistory(issue.getId())); } // 이슈를 수정한다 @Override public Issue modifyIssue(IssueApiForm issueApiForm, List<MultipartFile> files) { User user = this.convertToUser(issueApiForm.getToken()); IssueForm issueForm = this.convertToIssueForm(issueApiForm, user); return this.modifyIssue(user, issueForm, files); } // 이슈를 수정한다. @Override @Transactional public Issue modifyIssue(IssueForm issueForm, List<MultipartFile> multipartFiles) { User user = this.webAppUtil.getLoginUserObject(); return modifyIssue(user, issueForm, multipartFiles); } // 이슈를 수정한다. @Override @Transactional public Issue modifyIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) { // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. this.workspaceService.checkUseWorkspace(); this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId()); // 이슈 수정 권한 체크 this.verifyIssueModifyPermission(issueForm.getId()); // 프로젝트 유효성 체크 @@ -1266,14 +1299,14 @@ //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds()); // 담당부서 지정 if(issueForm.getDepartmentIds().size()>0){ this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds()); 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, this.webAppUtil.getLoginUser().getAccount()); this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount()); // 삭제된 첨부파일 처리 this.attachedFileService.removeAttachedFiles(issueForm.getRemoveFiles()); // 텍스트 에디터에 첨부한 파일을 이슈와 연결 @@ -1282,7 +1315,7 @@ this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields()); // 이슈 이력 등록 if (!StringUtils.isEmpty(detectIssueChange.toString())) { this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.MODIFY, detectIssueChange.toString()); this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString()); } // 사용자 시스템 기능 사용 정보 수집 log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_MODIFY)); src/main/java/kr/wisestone/owl/web/controller/ApiController.java
@@ -1,16 +1,12 @@ package kr.wisestone.owl.web.controller; import kr.wisestone.owl.constant.Constants; import kr.wisestone.owl.constant.MsgConstants; import kr.wisestone.owl.domain.Issue; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.service.GuideService; import kr.wisestone.owl.service.IssueService; import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.util.MapUtil; import kr.wisestone.owl.web.condition.GuideCondition; import kr.wisestone.owl.web.form.GuideForm; import kr.wisestone.owl.web.form.IssueApiForm; import kr.wisestone.owl.web.form.IssueForm; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; @@ -23,10 +19,6 @@ import java.util.HashMap; import java.util.Map; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Stack; @Controller public class ApiController extends BaseController { @@ -54,9 +46,17 @@ Map<String, Object> resJsonData = new HashMap<>(); IssueApiForm issueForm = IssueApiForm.make(ConvertUtil.convertJsonToMap(request.getParameter(Constants.REQ_KEY_CONTENT)), request.getFiles("file")); Issue issue = this.issueService.addApiIssue(issueForm); // 버전 생성 this.issueService.addIssueVersion(issue.getId()); if (issueForm == null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ERROR)); } if (issueForm.getApiType() == IssueApiForm.ApiType.add) { Issue issue = this.issueService.addApiIssue(issueForm); // 버전 생성 this.issueService.addIssueVersion(issue.getId()); } else { this.issueService.modifyIssue(issueForm, request.getFiles("file")); } return this.setSuccessMessage(resJsonData); } src/main/java/kr/wisestone/owl/web/form/IssueApiForm.java
@@ -1,7 +1,9 @@ package kr.wisestone.owl.web.form; import com.google.common.collect.Lists; import kr.wisestone.owl.constant.MsgConstants; import kr.wisestone.owl.domain.IssueCustomFieldValue; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.util.MapUtil; import kr.wisestone.owl.vo.CustomFieldVo; @@ -10,6 +12,12 @@ import java.util.*; public class IssueApiForm { public enum ApiType { add, modify } private String token; private String title; private String projectKey; @@ -20,6 +28,7 @@ private Date startDate; private Date endDate; private Date searchTime; private ApiType apiType; private List<DepartmentForm> departments = Lists.newArrayList(); private List<IssueCustomFieldValueForm> issueCustomFieldValues = Lists.newArrayList(); private List<Map<String, Object>> CustomFieldValues = Lists.newArrayList(); @@ -33,13 +42,21 @@ IssueApiForm form = ConvertUtil.convertMapToClass(content, IssueApiForm.class); form.setMultipartFiles(files); // api 타입 if (MapUtil.getString(content, "apiType") != null) { try { form.setApiType(ApiType.valueOf(MapUtil.getString(content, "apiType"))); } catch (Exception ex) { return null; } } // 사용자 필드 정보 if (MapUtil.getObject(content, "customFields") != null){ List<Map<String, Object>> customFields = (List)MapUtil.getObject(content, "customFields"); for (Map<String, Object> customField : customFields) { IssueCustomFieldValueForm issueCustomFieldValueForm = ConvertUtil.convertMapToClass(customField, IssueCustomFieldValueForm.class); form.addIssueCustomFieldValue(issueCustomFieldValueForm); Map<String, Object> customFieldVo = new HashMap<>(); customFieldVo.put("id", issueCustomFieldValueForm.getCustomFieldId()); @@ -177,7 +194,15 @@ CustomFieldValues = customFieldValues; } // public List<Map<String, Object>> getFiles() { public ApiType getApiType() { return apiType; } public void setApiType(ApiType apiType) { this.apiType = apiType; } // public List<Map<String, Object>> getFiles() { // return files; // } // src/main/resources/mybatis/query-template/issue-template.xml
@@ -510,11 +510,12 @@ <!-- 특정 사용자 정의 필드 값이 같은 이슈를 조회 --> <select id="findByCustomFieldValue" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition"> SELECT id FROM issue LEFT OUTER JOIN issue_custom_field_value issue_custom FORCE INDEX(issueIdIndex) ON issue.id = issue_custom.issue_id iss.id as id, iss.title as title FROM issue iss LEFT OUTER JOIN issue_custom_field_value issue_custom FORCE INDEX(issueIdIndex) ON iss.id = issue_custom.issue_id WHERE 1=1 AND issue.parent_issue_id IS NULL AND iss.parent_issue_id IS NULL <choose> <when test="useValues.size != 0"> AND issue_custom.use_value IN src/main/webapp/scripts/app/api/apiSetting.controller.js
@@ -97,9 +97,11 @@ let customFieldApiOverlaps = result.data.data; $scope.vm.form.customFields = []; customFieldApiOverlaps.forEach(function (customFieldApiOverlap) { $scope.vm.form.customFields.push(customFieldApiOverlap.customFieldVo); }); if (customFieldApiOverlaps != null) { customFieldApiOverlaps.forEach(function (customFieldApiOverlap) { $scope.vm.form.customFields.push(customFieldApiOverlap.customFieldVo); }); } } else { SweetAlert.swal($filter("translate")("issue.failedToIssueTypeListLookup"), result.data.message.message, "error"); // "이슈 유형 목록 조회 실패" src/main/webapp/views/api/apiOverlapAdd.html
File was deleted src/main/webapp/views/api/apiSettingOverlap.html
@@ -29,7 +29,7 @@ </div> <div class="element-box"> <div class="element-box" style="height: 600px"> <form role="form" name="apiSettingOverlapForm"> <div class="form-group"> <label><span translate="common.customField">사용자 정의 필드</span> </label>