OWL ITS + 탐지시스템(인터넷 진흥원)
jhjang
2021-12-01 a42f592181c23cb1d84d5b66b4b165aa855d57e2
- api 이슈 추가 기능 완료
28개 파일 변경됨
3개 파일 추가됨
794 ■■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/config/SecurityConfiguration.java 5 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/constant/MsgConstants.java 5 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/Issue.java 17 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java 3 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/ApiTokenService.java 8 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/AttachedFileService.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/CustomFieldApiOverlapService.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueApiDefaultService.java 1 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueCustomFieldValueService.java 3 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueDepartmentService.java 3 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueHistoryService.java 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueService.java 7 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/WorkspaceService.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/ApiTokenServiceImpl.java 33 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/AttachedFileServiceImpl.java 29 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/CustomFieldApiOverlapServiceImpl.java 8 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueApiDefaultServiceImpl.java 19 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueCustomFieldValueServiceImpl.java 23 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueDepartmentServiceImpl.java 17 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java 32 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 166 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/WorkspaceServiceImpl.java 28 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/util/CommonUtil.java 54 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/controller/ApiController.java 35 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/controller/IssueController.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/CustomFieldValueForm.java 24 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/IssueApiForm.java 195 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/IssueCustomFieldValueForm.java 24 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/IssueForm.java 23 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/migration/V1_11__Alter_Table.sql 3 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/issue-template.xml 17 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/config/SecurityConfiguration.java
@@ -1,6 +1,7 @@
package kr.wisestone.owl.config;
import kr.wisestone.owl.config.security.filter.AjaxSessionExpiredFilter;
import kr.wisestone.owl.config.security.filter.CustomAuthenticationFilter;
import kr.wisestone.owl.config.security.handler.AjaxAuthenticationEntryPoint;
import kr.wisestone.owl.config.security.handler.AjaxAuthenticationFailureHandler;
import kr.wisestone.owl.config.security.handler.AjaxAuthenticationSuccessHandler;
@@ -22,6 +23,7 @@
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
@@ -143,7 +145,10 @@
                .antMatchers("/guide/detail").permitAll()
                .antMatchers("/language/change").permitAll()
                .antMatchers("/security/*").permitAll()
                .antMatchers("/api/issue").permitAll()
                .antMatchers("/**/*").authenticated();
//        http.addFilter(new CustomAuthenticationFilter());
//        http.addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.rememberMe()
src/main/java/kr/wisestone/owl/constant/MsgConstants.java
@@ -149,6 +149,7 @@
    public static final String USER_NOT_EQUAL_PASSWORD = "USER_NOT_EQUAL_PASSWORD"; //  비밀번호가 맞지 않습니다.
    public static final String USER_NOT_EXIST = "USER_NOT_EXIST";   //  사용자가 존재하지 않습니다.
    public static final String USER_NOT_AUTHORIZED = "USER_NOT_AUTHORIZED"; //  사용자 인증 권한이 없습니다.
    public static final String ERROR_TOKEN = "USER_NOT_AUTHORIZED_TOKEN"; //  유효하지 않은 토큰입니다.
    public static final String USER_EXPIRED_PASSWORD = "USER_EXPIRED_PASSWORD"; //  비밀번호가 만료되었습니다.
    public static final String USER_RETURN_PASSWORD_NOT_PROVIDER_SOCIAL_JOIN_USER = "USER_RETURN_PASSWORD_NOT_PROVIDER_SOCIAL_JOIN_USER";   //  비밀번호 찾기 기능을 소셜 계정 가입 사용자는 사용할 수 없습니다.
    public static final String USER_NOT_USE_ACTIVE_STATUS = "USER_NOT_USE_ACTIVE_STATUS";   //  사용자는 활성 상태가 아니면 로그인할 수 없습니다.
@@ -226,4 +227,8 @@
    public static final String ISP_NOT_EXIST = "ISP_NOT_EXIST";   // ISP가 존재하지 않습니다.
    public static final String ISP_REMOVE_NOT_SELECT = "ISP_REMOVE_NOT_SELECT";   // 삭제할 ISP가 선택되지 않았습니다.
    public static final String PROJECT_NOT_INCLUDE_DEPARTMENT = "PROJECT_NOT_INCLUDE_DEPARTMENT";   // 선택한 부서 중 프로젝트에 참여하고 있지 않은 부서가 있습니다.
    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_USER_ERROR = "API_USER_ERROR";     // api 사용자 오류
}
src/main/java/kr/wisestone/owl/domain/Issue.java
@@ -1,5 +1,8 @@
package kr.wisestone.owl.domain;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
@@ -9,6 +12,8 @@
 * Created by wisestone on 2018-01-03.
 */
@Entity
@DynamicInsert
@DynamicUpdate
public class Issue extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    public static final String WORKSPACE_MANAGER = "WORKSPACE_MANAGER"; //  업무 공간 관리자
@@ -16,6 +21,9 @@
    public static final String REGISTER = "REGISTER";   //  이슈 등록자
    public static final String ASSIGNEE = "ASSIGNEE";   //  이슈 담당자
    public static final String DEPARTMENT = "DEPARTMENT";   //  이슈 담당부서
    public static final String IS_API_YES = "Y";
    public static final String IS_API_NO = "N";
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -26,6 +34,7 @@
    private Long issueNumber;
    private String startDate;
    private String completeDate;
    private String isApi;
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "project_id")
@@ -330,4 +339,12 @@
    public void setParentIssue(Issue parentIssue) {
        this.parentIssue = parentIssue;
    }
    public String isApi() {
        return isApi;
    }
    public void setApi(String api) {
        isApi = api;
    }
}
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java
@@ -1,6 +1,7 @@
package kr.wisestone.owl.mapper;
import kr.wisestone.owl.web.condition.IssueCondition;
import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition;
import kr.wisestone.owl.web.form.IssueForm;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@@ -15,6 +16,8 @@
public interface IssueMapper {
    List<Map<String, Object>> find(IssueCondition issueCondition);
    List<Map<String, Object>> findByCustomFieldValue(IssueCustomFieldValueCondition issueCustomFieldValueCondition);
    Long count(IssueCondition issueCondition);
    void insertBatch(@Param("issueForms") List<IssueForm> issueForms);
src/main/java/kr/wisestone/owl/service/ApiTokenService.java
@@ -1,12 +1,10 @@
package kr.wisestone.owl.service;
import kr.wisestone.owl.domain.ApiToken;
import kr.wisestone.owl.domain.CompanyField;
import kr.wisestone.owl.domain.CustomField;
import kr.wisestone.owl.domain.Event;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.vo.ApiTokenVo;
import kr.wisestone.owl.vo.CompanyFieldVo;
import kr.wisestone.owl.vo.EventVo;
import kr.wisestone.owl.vo.UserVo;
import kr.wisestone.owl.web.condition.ApiTokenCondition;
import kr.wisestone.owl.web.condition.CompanyFieldCondition;
import kr.wisestone.owl.web.condition.EventCondition;
@@ -30,5 +28,7 @@
    ApiTokenVo find();
    UserVo certification(String token);
    void remove(ApiTokenForm apiTokenForm);
}
src/main/java/kr/wisestone/owl/service/AttachedFileService.java
@@ -19,6 +19,8 @@
    List<AttachedFile> addAttachedFile(List<MultipartFile> multipartFiles, Map<String, Object> content);
    List<AttachedFile> addAttachedFile(Workspace workspace, Issue issue, List<Map<String, Object>> files);
    List<AttachedFileVo> findAttachedFile(Map<String, Object> resJsonData, AttachedFileCondition condition);
    List<AttachedFile> findByIssueId(Long issueId);
src/main/java/kr/wisestone/owl/service/CustomFieldApiOverlapService.java
@@ -6,9 +6,11 @@
import kr.wisestone.owl.web.form.IssueApiDefaultForm;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Map;
public interface CustomFieldApiOverlapService extends AbstractService<CustomFieldApiOverlap, Long, JpaRepository<CustomFieldApiOverlap, Long>> {
    void find(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form);
    List<CustomFieldApiOverlap> find(Long userId, Long issueTypeId);
    boolean modify(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form);
}
src/main/java/kr/wisestone/owl/service/IssueApiDefaultService.java
@@ -9,5 +9,6 @@
public interface IssueApiDefaultService extends AbstractService<IssueApiDefault, Long, JpaRepository<IssueApiDefault, Long>> {
    IssueApiDefault find(Map<String, Object> resJsonData, IssueApiDefaultForm form);
    IssueApiDefault find(IssueApiDefaultForm form);
    boolean modify(Map<String, Object> resJsonData, IssueApiDefaultForm form);
}
src/main/java/kr/wisestone/owl/service/IssueCustomFieldValueService.java
@@ -6,6 +6,7 @@
import kr.wisestone.owl.domain.enumType.CustomFieldType;
import kr.wisestone.owl.vo.IssueCustomFieldValueVo;
import kr.wisestone.owl.web.condition.IssueCondition;
import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
@@ -27,6 +28,8 @@
    boolean find(IssueCondition condition, Set<String> issueIds);
    Map<String, Object> find(IssueCustomFieldValueCondition issueCustomFieldValueCondition);
    List<Map<String, Object>> findInIssueIds(IssueCondition issueCondition);
    void removeIssueCustomFieldValuesByCustomFieldId(CustomField customField);
src/main/java/kr/wisestone/owl/service/IssueDepartmentService.java
@@ -2,6 +2,7 @@
import kr.wisestone.owl.domain.Issue;
import kr.wisestone.owl.domain.IssueDepartment;
import kr.wisestone.owl.domain.User;
import kr.wisestone.owl.domain.Workspace;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -13,6 +14,8 @@
    //담당부서
    void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds);
    void modifyIssueDepartment(Issue issue, User user, Workspace workspace, List<Long> departmentIds);
    void insertIssueDepartment(List<Map<String, Long>> issueAssigneeMaps);
    void removeIssueDepartment(Long projectId, List<Long> excludeUserIds);
src/main/java/kr/wisestone/owl/service/IssueHistoryService.java
@@ -18,8 +18,12 @@
    void addIssueHistory(Issue issue, IssueHistoryType issueHistoryType, String issueChangeDescription);
    void addIssueHistory(Issue issue, User user, IssueHistoryType issueHistoryType, String issueChangeDescription);
    void makeDescription(StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription);
    void makeDescription(User user, StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription);
    void findIssueHistory(Map<String, Object> resJsonData, IssueHistoryCondition issueHistoryCondition);
    List<IssueHistoryVo> findIssueHistory(Long issueId);
src/main/java/kr/wisestone/owl/service/IssueService.java
@@ -2,10 +2,12 @@
import kr.wisestone.owl.domain.Issue;
import kr.wisestone.owl.domain.IssueType;
import kr.wisestone.owl.domain.User;
import kr.wisestone.owl.domain.Workflow;
import kr.wisestone.owl.vo.IssueVo;
import kr.wisestone.owl.web.condition.IssueCondition;
import kr.wisestone.owl.web.condition.ProjectCondition;
import kr.wisestone.owl.web.form.IssueApiForm;
import kr.wisestone.owl.web.form.IssueForm;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -22,6 +24,11 @@
    Issue addIssue(IssueForm issueForm, List<MultipartFile> files);
    Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles);
    Issue addApiIssue(IssueApiForm issueApiForm);
    List<IssueVo> findIssue(Map<String, Object> resJsonData,
                            IssueCondition condition, Pageable pageable);
src/main/java/kr/wisestone/owl/service/WorkspaceService.java
@@ -42,6 +42,8 @@
    void checkUseWorkspace();
    Workspace checkUseWorkspace(User user, Long workspaceId);
    ModelAndView checkUseExcelDownload(Model model);
    boolean checkUseTraffic(Long fileSize);
src/main/java/kr/wisestone/owl/service/impl/ApiTokenServiceImpl.java
@@ -4,8 +4,10 @@
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.domain.ApiToken;
import kr.wisestone.owl.domain.User;
import kr.wisestone.owl.exception.OwlRuntimeException;
import kr.wisestone.owl.repository.ApiTokenRepository;
import kr.wisestone.owl.service.ApiTokenService;
import kr.wisestone.owl.util.ConvertUtil;
@@ -84,8 +86,19 @@
    }
    //JWT 복호화
    public UserVo getUser(String jwt) {
    private UserVo getUserVo(String jwt) {
        //결과값 = Claims
        Jws<Claims> claims = decryption(jwt);
        if (claims == null)
            return  null;
        ObjectMapper objectMapper = new ObjectMapper();
        //반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용
        return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class);
    }
    private Jws<Claims> decryption(String jwt) {
        //결과값 = Claims
        Jws<Claims> claims = null;
@@ -98,11 +111,9 @@
        } catch (Exception e) {
            log.debug(e.getMessage(), e);
        }
        ObjectMapper objectMapper = new ObjectMapper();
        //반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용
        return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class);
        return claims;
    }
    // 토큰 조회
    @Override
@@ -115,6 +126,18 @@
        return null;
    }
    // 토큰 사용자 인증
    @Override
    public UserVo certification(String token) {
         UserVo userVo = this.getUserVo(token);
         if (userVo != null){
             return userVo;
         } else  {
             throw new OwlRuntimeException(
                     this.messageAccessor.getMessage(MsgConstants.ERROR_TOKEN));
         }
    }
    // 토큰 삭제
    @Override
    public void remove(ApiTokenForm apiTokenForm) {
src/main/java/kr/wisestone/owl/service/impl/AttachedFileServiceImpl.java
@@ -119,6 +119,35 @@
        }
    }
    //  첨부 파일을 등록한다. - API 에서 사용
    @Override
    @Transactional
    public List<AttachedFile> addAttachedFile(Workspace workspace, Issue issue, List<Map<String, Object>> files) {
        if (workspace == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKSPACE_NOT_EXIST));
        }
        if (issue == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST));
        }
        if (files != null && files.size() > 0) {
            List<Map<String, Object>> convertFileMaps = Lists.newArrayList();
            for (Map<String, Object> file : files) {
                String fileName = MapUtil.getString(file, "fileName");
                String fileStr = MapUtil.getString(file, "file");
                String contentType = MapUtil.getString(file, "contentType");
                convertFileMaps.add(CommonUtil.makeFileMap(fileName, fileStr, contentType));
            }
            return this.addAttachedFiles(workspace, convertFileMaps, issue, null, AttachedType.SUMMER);
        }
        return null;
    }
    //  첨부 파일을 등록한다. - 이슈 생성, 수정에서 사용
    @Override
    @Transactional
src/main/java/kr/wisestone/owl/service/impl/CustomFieldApiOverlapServiceImpl.java
@@ -41,10 +41,14 @@
    }
    @Override
    public List<CustomFieldApiOverlap> find(Long userId, Long issueTypeId) {
        return this.customFieldApiOverlapRepository.findByUserIdAndIssueTypeId(userId, issueTypeId);
    }
    @Override
    @Transactional
    public void find(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form) {
        UserVo userVo = this.webAppUtil.getLoginUser();
        List<CustomFieldApiOverlap> customFieldApiOverlaps = this.customFieldApiOverlapRepository.findByUserIdAndIssueTypeId(userVo.getId(), form.getIssueTypeId());
        List<CustomFieldApiOverlap> customFieldApiOverlaps = this.find(form.getUserId(), form.getIssueTypeId());
        if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) {
            List<CustomFieldApiOverlapVo> customFieldApiOverlapVos =  Lists.newArrayList();
src/main/java/kr/wisestone/owl/service/impl/IssueApiDefaultServiceImpl.java
@@ -46,10 +46,9 @@
    @Override
    @Transactional
    public IssueApiDefault find(Map<String, Object> resJsonData, IssueApiDefaultForm form) {
        UserVo userVo = this.webAppUtil.getLoginUser();
        List<IssueApiDefault> issueApiDefaults = this.issueApiDefaultRepository.findByUserIdAndIssueTypeId(userVo.getId(), form.getIssueTypeId());
        if (issueApiDefaults != null && issueApiDefaults.size() > 0) {
            IssueApiDefault issueApiDefault = issueApiDefaults.get(0);
        form.setUserId(this.webAppUtil.getLoginId());
        IssueApiDefault issueApiDefault = this.find(form);
        if (issueApiDefault != null) {
            IssueApiDefaultVo issueApiDefaultVo = ConvertUtil.copyProperties(issueApiDefault, IssueApiDefaultVo.class);
            Project project = issueApiDefault.getProject();
            if (project != null) {
@@ -67,7 +66,17 @@
            }
            resJsonData.put(Constants.RES_KEY_CONTENTS, issueApiDefaultVo);
            return issueApiDefault;
        }
        return issueApiDefault;
    }
    @Override
    public IssueApiDefault find(IssueApiDefaultForm form) {
        if (form.getUserId() != null && form.getIssueTypeId() != null) {
            List<IssueApiDefault> issueApiDefaults = this.issueApiDefaultRepository.findByUserIdAndIssueTypeId(form.getUserId(), form.getIssueTypeId());
            if (issueApiDefaults != null && issueApiDefaults.size() > 0) {
                return issueApiDefaults.get(0);
            }
        }
        return null;
    }
src/main/java/kr/wisestone/owl/service/impl/IssueCustomFieldValueServiceImpl.java
@@ -333,6 +333,29 @@
        return customFieldSearch;
    }
    @Override
    public Map<String, Object> find(IssueCustomFieldValueCondition issueCustomFieldValueCondition) {
        if (issueCustomFieldValueCondition.getUseValues().size() > 0 || !StringUtils.isEmpty(issueCustomFieldValueCondition.getUseValue())) {
            issueCustomFieldValueCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
            //  사용자 정의 필드 값 검색 시작
            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;
            }
            return result;
        }
        return null;
    }
    //  이슈에서 저장한 사용자 정의 필드 값을 조회한다.
    @Override
    @Transactional(readOnly = true)
src/main/java/kr/wisestone/owl/service/impl/IssueDepartmentServiceImpl.java
@@ -1,10 +1,7 @@
package kr.wisestone.owl.service.impl;
import com.google.common.collect.Lists;
import kr.wisestone.owl.domain.Issue;
import kr.wisestone.owl.domain.IssueDepartment;
import kr.wisestone.owl.domain.IssueUser;
import kr.wisestone.owl.domain.Workspace;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.mapper.IssueDepartmentMapper;
import kr.wisestone.owl.mapper.IssueUserMapper;
import kr.wisestone.owl.repository.IssueDepartmentRepository;
@@ -42,6 +39,14 @@
    @Override
    @Transactional
    public void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds) {
        User user = this.webAppUtil.getLoginUserObject();
        modifyIssueDepartment(issue, user, workspace, departmentIds);
    }
    //  이슈 담당부서를 변경한다.
    @Override
    @Transactional
    public void modifyIssueDepartment(Issue issue, User user, Workspace workspace, List<Long> departmentIds) {
        List<Long> oldDepartmentIds = Lists.newArrayList();
        //  이전 담당 부서
@@ -69,8 +74,8 @@
                issueAssigneeMap.put("departmentId", departmentId); //담당부서
                issueAssigneeMap.put("issueId", issue.getId());
                issueAssigneeMap.put("workspaceId", workspace.getId());
                issueAssigneeMap.put("registerId", this.webAppUtil.getLoginId());
                issueAssigneeMap.put("modifyId", this.webAppUtil.getLoginId());
                issueAssigneeMap.put("registerId", user.getId());
                issueAssigneeMap.put("modifyId", user.getId());
                addIssueAssigneeMaps.add(issueAssigneeMap);
            }
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java
@@ -63,13 +63,22 @@
    @Override
    @Transactional
    public void addIssueHistory(Issue issue, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        User user = this.webAppUtil.getLoginUserObject();
        addIssueHistory(issue, user, issueHistoryType, issueChangeDescription);
    }
    //  이력 생성
    @Override
    @Transactional
    public void addIssueHistory(Issue issue, User user, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        IssueHistory issueHistory = new IssueHistory();
        issueHistory.setIssue(issue);
        issueHistory.setProject(issue.getProject());
        issueHistory.setIssueHistoryType(issueHistoryType);
        StringBuilder description = new StringBuilder();
        //  이력 정보를 만들어 낸다.
        this.makeDescription(description, issueHistoryType, issueChangeDescription);
        this.makeDescription(user, description, issueHistoryType, issueChangeDescription);
        issueHistory.setDescription(description.toString());
        this.issueHistoryRepository.saveAndFlush(issueHistory);
@@ -81,6 +90,13 @@
    //  이력 정보를 만들어 낸다.
    @Override
    public void makeDescription(StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        User user = this.webAppUtil.getLoginUserObject();
        makeDescription(user, description, issueHistoryType, issueChangeDescription);
    }
    //  이력 정보를 만들어 낸다.
    @Override
    public void makeDescription(User user, StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) {
        description.append("<div class=\"activity-text\">");
        //  생성, 수정, 삭제에 대해 기록을 남긴다.
@@ -90,9 +106,9 @@
                description.append("<span class='activity-timestamp'>");
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                description.append(this.webAppUtil.getLoginUser().getName());
                description.append(user.getName());
                description.append(" - ");
                description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount()));
                description.append(CommonUtil.decryptAES128(user.getAccount()));
                description.append(")");
                description.append("</span></h6>");
                break;
@@ -103,10 +119,10 @@
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                if (this.webAppUtil.getLoginUser() != null) {
                    description.append(this.webAppUtil.getLoginUser().getName());
                if (user != null) {
                    description.append(user.getName());
                    description.append(" - ");
                    description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount()));
                    description.append(CommonUtil.decryptAES128(user.getAccount()));
                }
                else {
                    description.append("OWL-ITS-SYSTEM");
@@ -124,9 +140,9 @@
                description.append("<span class=\"activity-timestamp\">");
                description.append(DateUtil.convertDateToStr(new Date()));
                description.append(" (");
                description.append(this.webAppUtil.getLoginUser().getName());
                description.append(user.getName());
                description.append(" - ");
                description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount()));
                description.append(CommonUtil.decryptAES128(user.getAccount()));
                description.append(")");
                description.append("</span></h6>");
                break;
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -21,10 +21,10 @@
import kr.wisestone.owl.util.DateUtil;
import kr.wisestone.owl.vo.*;
import kr.wisestone.owl.web.condition.IssueCondition;
import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition;
import kr.wisestone.owl.web.condition.IssueTypeCustomFieldCondition;
import kr.wisestone.owl.web.condition.ProjectCondition;
import kr.wisestone.owl.web.form.IssueCommentForm;
import kr.wisestone.owl.web.form.IssueForm;
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;
@@ -71,6 +71,15 @@
    @Autowired
    private SeverityService severityService;
    @Autowired
    private CustomFieldApiOverlapService customFieldApiOverlapService;
    @Autowired
    private IssueApiDefaultService issueApiDefaultService;
    @Autowired
    private ApiTokenService apiTokenService;
    @Autowired
    private CompanyFieldService companyFieldService;
@@ -182,12 +191,109 @@
    }
    //  API 를 통해 이슈 추가.
    @Override
    @Transactional
    public Issue addApiIssue(IssueApiForm issueApiForm) {
        if (issueApiForm.getIssueTypeId() == null) {
            throw new OwlRuntimeException(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 OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
        }
        // 프로젝트 입력
        Project project = issueType.getProject();
        if (project == null){
            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR));
        }
        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());
            issueApiDefaultForm.setIssueTypeId(issueForm.getIssueTypeId());
            IssueApiDefault issueApiDefault = this.issueApiDefaultService.find(issueApiDefaultForm);
            if (issueApiDefault != null) {
                ConvertUtil.copyProperties(issueApiDefault, issueForm);
                issueForm.setPriorityId(issueApiDefault.getPriority().getId());
                issueForm.setSeverityId(issueApiDefault.getSeverity().getId());
            }
            // 중복 값 하위 이슈로 처리하기
            CustomFieldApiOverlapForm customFieldApiOverlapForm = new CustomFieldApiOverlapForm();
            customFieldApiOverlapForm.setUserId(user.getId());
            customFieldApiOverlapForm.setIssueTypeId(issueForm.getIssueTypeId());
            IssueVo issueVo = this.findIssue(issueApiForm, user.getId());
            if (issueVo != null) {
                issueForm.setParentIssueId(issueVo.getId());
            }
            issueForm.setIsApi(Issue.IS_API_YES);
            // 사용자 정의 필드 설정
            issueForm.setIssueCustomFields(issueApiForm.getCustomFieldValues());
            // api 입력값 적용
            ConvertUtil.copyProperties(issueApiForm, issueForm);
            return addIssue(user, issueForm, issueApiForm.getMultipartFiles());
        } else {
            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR));
        }
    }
    // 중복된 상위 이슈 검색
    private IssueVo findIssue(IssueApiForm issueApiForm, Long userId) {
        IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
        List<CustomFieldApiOverlap> customFieldApiOverlaps = this.customFieldApiOverlapService.find(userId, issueApiForm.getIssueTypeId());
        if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) {
            for (CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                for (IssueCustomFieldValueForm issueCustomFieldValue : issueApiForm.getIssueCustomFieldValues()) {
                    if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValue.getCustomFieldId())) {
                        issueCustomFieldValueCondition.addUseValues(issueCustomFieldValue.getUseValue());
                    }
                }
            }
            List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
            if (results != null && results.size() > 0) {
                IssueVo issueVo = new IssueVo();
                ConvertUtil.convertMapToObject(results.get(0), issueVo);
                return issueVo;
            }
        }
        return null;
    }
    //  이슈를 생성한다.
    @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) {
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
        Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId());
        //  프로젝트 유효성 체크
        Project project = this.projectService.getProject(issueForm.getProjectId());
        //  이슈 유형 유효성 체크
@@ -216,7 +322,7 @@
        issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project));    //  각 프로젝트의 고유 이슈 번호 생성
        this.issueRepository.saveAndFlush(issue);
        issue = this.issueRepository.saveAndFlush(issue);
        issue.setReverseIndex(issue.getId() * -1);  //  쿼리 속도 개선을 위해 리버스 인덱스 생성
        //  담당자 지정
@@ -230,32 +336,34 @@
        //  HOSTING 정보 저장
        this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields());
        //  첨부 파일 저장
        //  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.checkNotHaveIssueIdAttachedFile(issue, issueForm);
        //  사용자 정의 필드 저장
        this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields());
        //  이슈 이력 생성
        this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.ADD, null);
        this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null);
        //  이슈 위험 관리 생성
        this.issueRiskService.addIssueRisk(issue, project.getWorkspace());
        //  영속성 컨텍스트 비우기
        this.clear();
        //  이슈 생성, 삭제시 예약 이메일에 등록해놓는다.
        this.reservationIssueEmail(issue.getId(), EmailType.ISSUE_ADD);
        this.reservationIssueEmail(issue, EmailType.ISSUE_ADD);
        //  사용자 시스템 기능 사용 정보 수집
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ADD));
        UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class);
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD));
        return issue;
    }
    //  이슈 생성, 삭제시 예약 이메일에 등록해놓는다.
    private void reservationIssueEmail(Long id, EmailType emailType) {
        Issue issue = this.getIssue(id);
    private void reservationIssueEmail(Issue issue, EmailType emailType) {
        Map<String, Object> issueMap = new HashMap<>();
        //  이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다.
        this.makeIssueMapToIssue(issue, issueMap);
@@ -1125,12 +1233,14 @@
    private List<Map<String, Object>> convertMultipartFileToFile(List<MultipartFile> multipartFiles) {
        List<Map<String, Object>> convertFileMaps = Lists.newArrayList();
        for (MultipartFile multipartFile : multipartFiles) {
            try {
                Map<String, Object> fileMap = CommonUtil.makeFileMap(multipartFile);
                convertFileMaps.add(fileMap);
            } catch (Exception e) {
                log.debug("multipartFile -> file 변환 오류" + e.getMessage());
        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());
                }
            }
        }
@@ -1484,7 +1594,7 @@
        }
        //  이슈 생성, 삭제시 예약 이메일에 등록해놓는다.
        this.reservationIssueEmail(issue.getId(), EmailType.ISSUE_REMOVE);
        this.reservationIssueEmail(issue, EmailType.ISSUE_REMOVE);
        //  이슈 삭제
        this.issueRepository.delete(issue);
@@ -2502,7 +2612,7 @@
        //  사용자 시스템 기능 사용 정보 수집
        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); //mailType.ISSUE_SEND - 템플릿 설정
        this.systemEmailService.directEmail(issueForm.getSendEmails().toArray(new String[issueForm.getSendEmails().size()]), EmailType.ISSUE_SEND, issueMap, null);
    }
    //  예약 발생 이슈를 실행한다
@@ -2510,7 +2620,6 @@
    @Transactional
    public void reservationIssue() {
        List<IssueReservation> issueReservations = this.issueReservationService.findByIssueReservationTypeNotNull();
        Calendar calendar = Calendar.getInstance();
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
@@ -2675,18 +2784,13 @@
    @Override
    public void modifyParentIssue(IssueForm issueDownForm) {
        Issue issue = this.getIssue(issueDownForm.getId()); //하위 이슈
        Long newParentIssueId = issueDownForm.getParentIssueId(); //변경할 하위이슈의 상위이슈
        Issue parentIssue = issue.getParentIssue(); //변경 전 하위이슈의 상위이슈
        Long newParentIssueId = issueDownForm.getParentIssueId(); //변경할 하위이슈의 상위이슈
        StringBuilder sb = new StringBuilder();
        Issue parentIssue = issue.getParentIssue(); //변경 전 하위이슈의 상위이슈
        if(parentIssue != null){ //변경 전 하위이슈의 상위이슈가 존재 할 경우
            this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
            this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString());
        }
        if (newParentIssueId != null) { // 추가 할 경우
           // todo 이전 하위 일감 히스토리기록 필요
            // todo 이전 하위 일감 히스토리기록 필요
            parentIssue = this.getIssue(newParentIssueId); //상위이슈(myIssue)
            issue.setParentIssue(parentIssue); //myIssue를 하위이슈의 상위이슈로 set
            this.issueHistoryService.detectDownIssues(IssueHistoryType.ADD, issue, sb); //issue = 하위이슈
@@ -2716,7 +2820,7 @@
        }
    }
    @Override
    /*@Override
    @Transactional
    public void findMailTargetAll(Map<String, Object> resJsonData, IssueCondition condition, Pageable pageable) {
        IssueVo issueVo = new IssueVo();
@@ -2752,7 +2856,7 @@
        resJsonData.put(Constants.RES_KEY_CONTENTS, emailList);
        resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(),
                totalPage, totalCount));
    }
    }*/
    /*@Override
    @Transactional
src/main/java/kr/wisestone/owl/service/impl/WorkspaceServiceImpl.java
@@ -553,25 +553,47 @@
    @Override
    @Transactional
    public void checkUseWorkspace() {
        Workspace workspace = this.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
        User user = this.webAppUtil.getLoginUserObject();
        Workspace workspace = this.getWorkspace(user.getLastWorkspaceId());
        this.checkUseWorkspace(user, workspace.getId());
    }
    //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
    @Override
    @Transactional
    public Workspace checkUseWorkspace(User user, Long workspaceId) {
        if (user == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.USER_NOT_EXIST));
        }
        if (workspaceId == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKSPACE_NOT_EXIST));
        }
        Workspace workspace = this.getWorkspace(workspaceId);
        if (workspace.getServiceType().equals(ServiceType.UNUSED)) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKSPACE_USE_PERIOD_EXCESS));
        }
        UserWorkspace userWorkspace = this.userWorkspaceService.findByUserIdAndWorkspaceId(this.webAppUtil.getLoginId(), workspace.getId());
        UserWorkspace userWorkspace = this.userWorkspaceService.findByUserIdAndWorkspaceId(user.getId(), workspace.getId());
        if (!userWorkspace.getUseYn()) {
            //  해당 사용자가 관리하는 업무 공간를 마지막 접근 업무 공간로 변경한다.
            this.userService.updateLastMyWorkspace(userWorkspace.getUser());
            //  비활성 사용자는 더이상 해당 업무 공간에 있으면 안된다.
            this.simpMessagingTemplate.convertAndSendToUser(this.webAppUtil.getLoginUser().getAccount(), "/notification/workspace-remove", this.messageAccessor.getMessage(MsgConstants.WORKSPACE_OUT, workspace.getName()));
            this.simpMessagingTemplate.convertAndSendToUser(user.getAccount(), "/notification/workspace-remove", this.messageAccessor.getMessage(MsgConstants.WORKSPACE_OUT, workspace.getName()));
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKSPACE_INCLUDE_DISABLED));
        }
        return workspace;
    }
    //  사용 공간에서 로그인한 사용자가 비활성인지 확인하고 비활성일 경우 엑셀 다운로드를 금지한다.
src/main/java/kr/wisestone/owl/util/CommonUtil.java
@@ -344,6 +344,24 @@
        return fileMap;
    }
    //  string file 정보를 file Map 형태로 변경한다.
    public static Map<String, Object> makeFileMap(String fileName, String file, String contentType) {
        Map<String, Object> fileMap = new HashMap<>();
        try {
            byte[] bytes = Base64.decodeBase64(file);
            fileMap.put("fileName", fileName);
            fileMap.put("fileSize", bytes.length);
            fileMap.put("contentType", contentType);
            fileMap.put("file", CommonUtil.bytesToFile(fileName, bytes));
        } catch (Exception e) {
            LOGGER.debug(e.getMessage());
        }
        return fileMap;
    }
    public static String getPostDataString(Map<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
@@ -378,6 +396,42 @@
        return convertFile;
    }
    // string을 파일로 변환
    public static File stringToFile(String fileName, String file) {
        byte[] bytes = null;
        try {
            bytes = Base64.decodeBase64(file);
        } catch (Exception ex) {
            LOGGER.debug("string to bytes 변환 오류");
        }
        if (bytes != null) {
            return bytesToFile(fileName, bytes);
        }
        return  null;
    }
    // bytes를 파일로 변환
    public static File bytesToFile(String fileName, byte[] bytes) {
        File convertFile = new File(WebAppUtil.getContextRealPath() + TMP_UPLOAD_FOLDER + getFileNameByUUID(fileName));
        if (!convertFile.exists()) {
            convertFile.mkdirs();
        }
        try{
            FileOutputStream lFileOutputStream = new FileOutputStream(convertFile);
            lFileOutputStream.write(bytes);
            lFileOutputStream.close();
        }catch (IllegalStateException | IOException e) {
            LOGGER.debug("bytes 파일 file 변환 오류");
        }
        return convertFile;
    }
    public static InputStream getFileInputStream(String strPath, String strNewFileName){
        InputStream objInputStream = null;
src/main/java/kr/wisestone/owl/web/controller/ApiController.java
@@ -1,9 +1,15 @@
package kr.wisestone.owl.web.controller;
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.domain.Issue;
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;
@@ -12,6 +18,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@@ -20,22 +27,36 @@
public class ApiController extends BaseController {
    @Autowired
    private GuideService guideService;
    private IssueService issueService;
    //  이슈 추가
    @RequestMapping(value = "api/issue", produces = MediaType.APPLICATION_JSON_VALUE)
    //  이슈 추가(json 방식으로 파일전송)
//    @RequestMapping(value = "api/issue", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
//    public
//    @ResponseBody
//    Map<String, Object> addIssue(@RequestBody Map<String, Map<String, Object>> params) {
//        Map<String, Object> resJsonData = new HashMap<>();
//
//        IssueApiForm issueForm = IssueApiForm.make(params.get(Constants.REQ_KEY_CONTENT));
//        Issue issue = this.issueService.addApiIssue(issueForm);
//        //  버전 생성
//        this.issueService.addIssueVersion(issue.getId());
//        return this.setSuccessMessage(resJsonData);
//    }
    @RequestMapping(value = "api/issue", method = RequestMethod.POST)
    public
    @ResponseBody
    Map<String, Object> add(@RequestBody Map<String, Map<String, Object>> params) {
    Map<String, Object> addIssue(MultipartHttpServletRequest request) throws Exception {
        Map<String, Object> resJsonData = new HashMap<>();
        // todo
        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());
        return this.setSuccessMessage(resJsonData);
    }
    //  이슈 조회
    @RequestMapping(value = "/api/issuelist", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @RequestMapping(value = "/api/issueList", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public
    @ResponseBody
    Map<String, Object> find(@RequestBody Map<String, Map<String, Object>> params) {
src/main/java/kr/wisestone/owl/web/controller/IssueController.java
@@ -172,7 +172,7 @@
        Map<String, Object> resJsonData = new HashMap<>();
        Pageable pageable = this.pageUtil.convertPageable(this.getPageVo(params));
        this.issueService.findMailTargetAll(resJsonData, IssueCondition.make(params.get(Constants.REQ_KEY_CONTENT)), pageable);
//        this.issueService.findMailTargetAll(resJsonData, IssueCondition.make(params.get(Constants.REQ_KEY_CONTENT)), pageable);
        return this.setSuccessMessage(resJsonData);
    }
src/main/java/kr/wisestone/owl/web/form/CustomFieldValueForm.java
New file
@@ -0,0 +1,24 @@
package kr.wisestone.owl.web.form;
public class CustomFieldValueForm {
    private Long customFieldId;
    private String value;
    public CustomFieldValueForm(){}
    public Long getCustomFieldId() {
        return customFieldId;
    }
    public void setCustomFieldId(Long customFieldId) {
        this.customFieldId = customFieldId;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
src/main/java/kr/wisestone/owl/web/form/IssueApiForm.java
New file
@@ -0,0 +1,195 @@
package kr.wisestone.owl.web.form;
import com.google.common.collect.Lists;
import kr.wisestone.owl.domain.IssueCustomFieldValue;
import kr.wisestone.owl.util.ConvertUtil;
import kr.wisestone.owl.util.MapUtil;
import kr.wisestone.owl.vo.CustomFieldVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
public class IssueApiForm {
    private String token;
    private String title;
    private String projectKey;
    private String description;
    private Long issueTypeId;
    private Long priorityId;
    private Long severityId;
    private Date startDate;
    private Date endDate;
    private Date searchTime;
    private List<DepartmentForm> departments = Lists.newArrayList();
    private List<IssueCustomFieldValueForm> issueCustomFieldValues = Lists.newArrayList();
    private List<Map<String, Object>> CustomFieldValues = Lists.newArrayList();
//    private List<Map<String, Object>> files = Lists.newArrayList();
    private List<MultipartFile> multipartFiles = Lists.newArrayList();
    public IssueApiForm() {
    }
    public static IssueApiForm make(Map<String, Object> content, List<MultipartFile> files) {
        IssueApiForm form = ConvertUtil.convertMapToClass(content, IssueApiForm.class);
        form.setMultipartFiles(files);
        //  사용자 필드 정보
        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());
                customField.put("customFieldVo", customFieldVo);
                List<String> useValues = Lists.newArrayList();
                useValues.add(issueCustomFieldValueForm.getUseValue());
                customField.put("useValues", useValues);
                form.addCustomFieldValue(customField);
            }
        }
        // 첨부 파일
//        if (MapUtil.getObject(content, "files") != null){
//            form.setFiles((List)MapUtil.getObject(content, "files"));
//        }
        return form;
    }
    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getProjectKey() {
        return projectKey;
    }
    public void setProjectKey(String projectKey) {
        this.projectKey = projectKey;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Long getIssueTypeId() {
        return issueTypeId;
    }
    public void setIssueTypeId(Long issueTypeId) {
        this.issueTypeId = issueTypeId;
    }
    public Long getPriorityId() {
        return priorityId;
    }
    public void setPriorityId(Long priorityId) {
        this.priorityId = priorityId;
    }
    public Long getSeverityId() {
        return severityId;
    }
    public void setSeverityId(Long severityId) {
        this.severityId = severityId;
    }
    public List<DepartmentForm> getDepartments() {
        return departments;
    }
    public void setDepartments(List<DepartmentForm> departments) {
        this.departments = departments;
    }
    public Date getStartDate() {
        return startDate;
    }
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }
    public Date getEndDate() {
        return endDate;
    }
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }
    public Date getSearchTime() {
        return searchTime;
    }
    public void setSearchTime(Date searchTime) {
        this.searchTime = searchTime;
    }
    public List<IssueCustomFieldValueForm> getIssueCustomFieldValues() {
        return issueCustomFieldValues;
    }
    public void setIssueCustomFieldValues(List<IssueCustomFieldValueForm> issueCustomFieldValues) {
        this.issueCustomFieldValues = issueCustomFieldValues;
    }
    public void addIssueCustomFieldValue(IssueCustomFieldValueForm issueCustomFieldValueForm) {
        if (this.issueCustomFieldValues != null) {
            this.issueCustomFieldValues.add(issueCustomFieldValueForm);
        }
    }
    public void addCustomFieldValue(Map<String, Object> map) {
        if (this.CustomFieldValues != null) {
            this.CustomFieldValues.add(map);
        }
    }
    public List<Map<String, Object>> getCustomFieldValues() {
        return CustomFieldValues;
    }
    public void setCustomFieldValues(List<Map<String, Object>> customFieldValues) {
        CustomFieldValues = customFieldValues;
    }
//    public List<Map<String, Object>> getFiles() {
//        return files;
//    }
//
//    public void setFiles(List<Map<String, Object>> files) {
//        this.files = files;
//    }
    public List<MultipartFile> getMultipartFiles() {
        return multipartFiles;
    }
    public void setMultipartFiles(List<MultipartFile> multipartFiles) {
        this.multipartFiles = multipartFiles;
    }
}
src/main/java/kr/wisestone/owl/web/form/IssueCustomFieldValueForm.java
New file
@@ -0,0 +1,24 @@
package kr.wisestone.owl.web.form;
public class IssueCustomFieldValueForm {
    private Long customFieldId;
    private String useValue;
    public IssueCustomFieldValueForm(){}
    public Long getCustomFieldId() {
        return customFieldId;
    }
    public void setCustomFieldId(Long customFieldId) {
        this.customFieldId = customFieldId;
    }
    public String getUseValue() {
        return useValue;
    }
    public void setUseValue(String useValue) {
        this.useValue = useValue;
    }
}
src/main/java/kr/wisestone/owl/web/form/IssueForm.java
@@ -40,7 +40,9 @@
    private List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
    private List<Map<String, Object>> issueIspFields = Lists.newArrayList();
    private List<Map<String, Object>> issueHostingFields = Lists.newArrayList();
    private List<Map<String, Object>> files = Lists.newArrayList(); // api용 첨부파일
    private Long parentIssueId; // 상위 이슈
    private String isApi;
    public IssueForm() {
    }
@@ -110,6 +112,11 @@
        //  HOSTING 필드 정보
        if (MapUtil.getObject(params, "issueHostingFields") != null){
            form.setIssueHostingFields((List)MapUtil.getObject(params, "issueHostingFields"));
        }
        //  api 첨부파일
        if (MapUtil.getObject(params, "files") != null){
            form.setFiles((List)MapUtil.getObject(params, "files"));
        }
        return form;
    }
@@ -333,4 +340,20 @@
    public void setParentIssueId(Long parentIssueId) {
        this.parentIssueId = parentIssueId;
    }
    public String getIsApi() {
        return isApi;
    }
    public void setIsApi(String isApi) {
        this.isApi = isApi;
    }
    public List<Map<String, Object>> getFiles() {
        return files;
    }
    public void setFiles(List<Map<String, Object>> files) {
        this.files = files;
    }
}
src/main/resources/migration/V1_11__Alter_Table.sql
@@ -209,3 +209,6 @@
-- issue_type 테이블 업체,ISP,호스팅 컬럼 추가
ALTER TABLE `issue_type` ADD COLUMN  `use_partner` BIGINT(11) NOT NULL DEFAULT '0';
-- api 이슈 여부
ALTER TABLE `issue` ADD COLUMN  `is_api` VARCHAR(1) NOT NULL DEFAULT 'N';
src/main/resources/mybatis/query-template/issue-template.xml
@@ -482,5 +482,22 @@
        issue WHERE issue_status_id = #{issueStatusId};
    </select>
    <!--    특정 사용자 정의 필드 값이 같은 이슈를 조회 -->
    <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
        WHERE 1=1
        AND issue.parent_issue_id IS NULL
        <choose>
            <when test="useValues.size != 0">
                AND issue_custom.use_value IN
                <foreach collection="useValues" item="item" index="index" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </when>
        </choose>
    </select>
</mapper>