OWL ITS + 탐지시스템(인터넷 진흥원)
wyu
2021-12-05 43a8e9281c71f21b0e683e63def386d1ec0209bd
Merge branch 'master' of http://192.168.0.25:9001/r/owl-kisa
2개 파일 추가됨
18개 파일 변경됨
633 ■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/data/CheckIssueData.java 93 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/IssueUser.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueHistoryService.java 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueService.java 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/ProjectRoleUserService.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/UserWorkspaceService.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/CustomFieldApiOverlapServiceImpl.java 3 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueCustomFieldValueServiceImpl.java 9 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java 18 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 297 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/ProjectRoleUserServiceImpl.java 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/ProjectServiceImpl.java 40 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/UserWorkspaceServiceImpl.java 7 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/WidgetServiceImpl.java 12 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/IssueDownVo.java 93 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/IssueVo.java 17 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/IssueApiForm.java 9 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/IssueForm.java 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/system_prod.properties 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueDetail.controller.js 3 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/data/CheckIssueData.java
New file
@@ -0,0 +1,93 @@
package kr.wisestone.owl.data;
import kr.wisestone.owl.config.CommonConfiguration;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.service.*;
import kr.wisestone.owl.util.ConvertUtil;
import kr.wisestone.owl.web.form.IssueForm;
import org.springframework.beans.factory.annotation.Autowired;
// issue 유효성 체크용 클래스
public class CheckIssueData {
    Issue issue;
    IssueStatus oldIssueStatus;
    IssueStatus newIssueStatus;
    Project project;
    IssueType issueType;
    Priority priority;
    Severity severity;
    public CheckIssueData() {}
    public Issue getIssue() {
        return issue;
    }
    public void setIssue(Issue issue) {
        this.issue = issue;
    }
    public IssueStatus getOldIssueStatus() {
        return oldIssueStatus;
    }
    public void setOldIssueStatus(IssueStatus oldIssueStatus) {
        this.oldIssueStatus = oldIssueStatus;
    }
    public IssueStatus getNewIssueStatus() {
        return newIssueStatus;
    }
    public void setNewIssueStatus(IssueStatus newIssueStatus) {
        this.newIssueStatus = newIssueStatus;
    }
    public Project getProject() {
        return project;
    }
    public void setProject(Project project) {
        this.project = project;
    }
    public IssueType getIssueType() {
        return issueType;
    }
    public void setIssueType(IssueType issueType) {
        this.issueType = issueType;
    }
    public Priority getPriority() {
        return priority;
    }
    public void setPriority(Priority priority) {
        this.priority = priority;
    }
    public Severity getSeverity() {
        return severity;
    }
    public void setSeverity(Severity severity) {
        this.severity = severity;
    }
    //  변경된 값 설정
    public Issue SetIssue(IssueForm issueForm) {
        Issue issue = this.getIssue();
        ConvertUtil.copyProperties(issueForm, issue, "id");
        issue.setProject(getProject());
        issue.setIssueStatus(getNewIssueStatus());
        issue.setIssueType(getIssueType());
        issue.setPriority(getPriority());
        issue.setSeverity(getSeverity());
        issue.setStartDate(issueForm.getStartDate());
        issue.setCompleteDate(issueForm.getCompleteDate());
        return issue;
    }
}
src/main/java/kr/wisestone/owl/domain/IssueUser.java
@@ -15,7 +15,7 @@
    @JoinColumn(name = "user_id")
    private User user;
    @ManyToOne(fetch = FetchType.LAZY)
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "issue_id")
    private Issue issue;
src/main/java/kr/wisestone/owl/service/IssueHistoryService.java
@@ -1,5 +1,6 @@
package kr.wisestone.owl.service;
import kr.wisestone.owl.data.CheckIssueData;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.domain.enumType.IssueHistoryType;
import kr.wisestone.owl.service.impl.IssueHistoryServiceImpl;
@@ -28,7 +29,8 @@
    List<IssueHistoryVo> findIssueHistory(Long issueId);
    StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List<MultipartFile> files);
    StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus oldIssueStatus, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List<MultipartFile> files);
    StringBuilder detectIssueChange(IssueForm issueForm, CheckIssueData data, List<MultipartFile> files);
    void detectProject(Issue issue, IssueForm issueForm, StringBuilder description, Project project);
@@ -36,7 +38,7 @@
    void detectIssuePriority(Issue issue, IssueForm issueForm, StringBuilder description, Priority priority);
    void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus issueStatus);
    void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus oldIssueStatus, IssueStatus issueStatus);
    void detectReservationIssueStatus(Issue issue, StringBuilder description, IssueStatus issueStatus);
src/main/java/kr/wisestone/owl/service/IssueService.java
@@ -28,7 +28,9 @@
    Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles);
    Issue addApiIssue(IssueApiForm issueApiForm);
    Issue modifyIssue(IssueApiForm issueApiForm, List<MultipartFile> files);
    List<Issue> modifyIssue(IssueApiForm issueApiForm, List<MultipartFile> files);
    List<IssueVo> findIssue(IssueApiForm issueApiform);
    List<IssueVo> findIssue(Map<String, Object> resJsonData,
                            IssueCondition condition, Pageable pageable);
@@ -47,7 +49,7 @@
    void removeIssues(IssueForm issueForm);
    void modifyIssueStatus(IssueForm issueForm);
    void modifyIssueStatus(IssueForm issueForm, User user);
    Issue getIssue(Long taskId);
src/main/java/kr/wisestone/owl/service/ProjectRoleUserService.java
@@ -20,5 +20,5 @@
    Map<String, Object> findProjectManager(Long userId);
    boolean checkProjectManager(Project project);
    boolean checkProjectManager(Project project, User user);
}
src/main/java/kr/wisestone/owl/service/UserWorkspaceService.java
@@ -35,7 +35,7 @@
    UserWorkspace getUserWorkspace(Long id);
    boolean checkWorkspaceManager();
    boolean checkWorkspaceManager(User user);
    List<UserWorkspace> findByWorkspaceId(Long workspaceId);
src/main/java/kr/wisestone/owl/service/impl/CustomFieldApiOverlapServiceImpl.java
@@ -48,7 +48,8 @@
    @Override
    @Transactional
    public void find(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form) {
        List<CustomFieldApiOverlap> customFieldApiOverlaps = this.find(form.getUserId(), form.getIssueTypeId());
        Long userId = this.webAppUtil.getLoginId();
        List<CustomFieldApiOverlap> customFieldApiOverlaps = this.find(userId, form.getIssueTypeId());
        if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) {
            List<CustomFieldApiOverlapVo> customFieldApiOverlapVos =  Lists.newArrayList();
src/main/java/kr/wisestone/owl/service/impl/IssueCustomFieldValueServiceImpl.java
@@ -1,9 +1,11 @@
package kr.wisestone.owl.service.impl;
import com.google.common.collect.Lists;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.domain.enumType.CustomFieldType;
import kr.wisestone.owl.domain.enumType.IssueHistoryType;
import kr.wisestone.owl.exception.OwlRuntimeException;
import kr.wisestone.owl.mapper.IssueCustomFieldValueMapper;
import kr.wisestone.owl.repository.IssueCustomFieldValueRepository;
import kr.wisestone.owl.service.*;
@@ -76,7 +78,12 @@
        }
        if (issueCustomFieldValues.size() > 0) {
            this.issueCustomFieldValueRepository.saveAll(issueCustomFieldValues);
            try {
                this.issueCustomFieldValueRepository.saveAll(issueCustomFieldValues);
            } catch (Exception ex) {
                throw new OwlRuntimeException(
                        this.messageAccessor.getMessage(MsgConstants.CUSTOM_FIELD_NOT_EXIST));
            }
        }
    }
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java
@@ -4,6 +4,7 @@
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.constant.ElasticSearchConstants;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.data.CheckIssueData;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.domain.enumType.CustomFieldType;
import kr.wisestone.owl.domain.enumType.IssueHistoryType;
@@ -316,7 +317,13 @@
    //  이슈 변경 내역을 추출한다.
    @Override
    public StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List<MultipartFile> files) {
    public StringBuilder detectIssueChange(IssueForm issueForm, CheckIssueData data, List<MultipartFile> files) {
        return this.detectIssueChange(data.getIssue(), issueForm, data.getProject(), data.getOldIssueStatus(), data.getNewIssueStatus(), data.getIssueType(), data.getPriority(), data.getSeverity(), files);
    }
    //  이슈 변경 내역을 추출한다.
    @Override
    public StringBuilder detectIssueChange(Issue issue, IssueForm issueForm, Project project, IssueStatus oldIssueStatus, IssueStatus issueStatus, IssueType issueType, Priority priority, Severity severity, List<MultipartFile> files) {
        StringBuilder description = new StringBuilder();
        //  이슈 프로젝트 변경 정보를 기록한다.
@@ -326,7 +333,7 @@
        //  이슈 우선순위 변경 정보를 기록한다.
        this.detectIssuePriority(issue, issueForm, description, priority);
        //  이슈 상태 변경 정보를 기록한다.
        this.detectIssueStatus(issue, issueForm, description, issueStatus);
        this.detectIssueStatus(issue, issueForm, description, oldIssueStatus, issueStatus);
        //  이슈 타입 변경 정보를 기록한다.
        this.detectIssueType(issue, issueForm, description, issueType);
        //  이슈에 첨부된 파일에 대해 변경 정보를 기록한다.
@@ -407,11 +414,12 @@
    //  이슈 상태 변경 정보를 기록한다.
    @Override
    public void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus issueStatus) {
        if (!issue.getIssueStatus().getId().equals(issueForm.getIssueStatusId())) {
    @Transactional
    public void detectIssueStatus(Issue issue, IssueForm issueForm, StringBuilder description, IssueStatus oldIssueStatus, IssueStatus issueStatus) {
        if (!oldIssueStatus.getId().equals(issueForm.getIssueStatusId())) {
            String title = "<span translate=\"common.updateHasStatus\">상태가 변경되었습니다.</span>";
            //  이력 정보를 html 태그로 만들어 준다.
            this.makeIssueHistoryHtml(description, title, issue.getIssueStatus().getName(), issueStatus.getName());
            this.makeIssueHistoryHtml(description, title, oldIssueStatus.getName(), issueStatus.getName());
            //  이슈 위험 관리에 상태 변경 정보를 업데이트한다. - 담당자 변경
            this.issueRiskService.modifyIssueRisk(issue, true, false, issueForm.getIssueStatusId());
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -7,6 +7,7 @@
import kr.wisestone.owl.constant.ElasticSearchConstants;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.constant.UsePartner;
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;
@@ -52,9 +53,6 @@
    private IssueRepository issueRepository;
    @Autowired
    private IssueTableConfigService issueTableConfigService;
    @Autowired
    private ProjectService projectService;
    @Autowired
@@ -77,15 +75,6 @@
    @Autowired
    private ApiTokenService apiTokenService;
    @Autowired
    private CompanyFieldService companyFieldService;
    @Autowired
    private IspFieldService ispFieldService;
    @Autowired
    private HostingFieldService hostingFieldService;
    @Autowired
    private CommonConfiguration configuration;
@@ -157,6 +146,9 @@
    private UserWorkspaceService userWorkspaceService;
    @Autowired
    private WorkflowDepartmentService workflowDepartmentService;
    @Autowired
    private IssueRelationService issueRelationService;
    @Autowired
@@ -199,6 +191,28 @@
        if (issueType == null){
            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
        }
        Workflow workflow = issueType.getWorkflow();
        // 이슈 상태가 지정되어 있지 않을 경우 초기값으로 지정
        if (issueApiForm.getIssueStatusId() == null) {
            List<IssueStatusVo> issueStatusVos = issueStatusService.findByWorkflowId(workflow.getId());
            IssueStatusVo issueStatusVo = issueStatusVos.get(0);
            issueApiForm.setIssueStatusId(issueStatusVo.getId());
        }
        // 워크플로우 상태에 따른 담당부서 가져오기
        if (issueApiForm.getIssueStatusId() != null) {
            WorkflowDepartmentCondition workflowDepartmentCondition = new WorkflowDepartmentCondition();
            workflowDepartmentCondition.setIssueStatusId(issueApiForm.getIssueStatusId());
            workflowDepartmentCondition.setWorkflowId(workflow.getId());
            List<WorkflowDepartmentVo> workflowDepartmentVos = this.workflowDepartmentService.find(workflowDepartmentCondition);
            for (WorkflowDepartmentVo workflowDepartmentVo : workflowDepartmentVos) {
                issueForm.addDepartmentId(workflowDepartmentVo.getDepartmentVo().getId());
            }
        }
        // 프로젝트 입력
        Project project = issueType.getProject();
@@ -341,7 +355,7 @@
        //  담당자 지정
        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
        //  담당부서 지정
        this.issueDepartmentService.modifyIssueDepartment(issue, project.getWorkspace(), issueForm.getDepartmentIds());
        this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds());
        //  업체 정보 저장
        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
        //  ISP 정보 저장
@@ -568,7 +582,8 @@
        //  이슈 아이디 초기화
        issueCondition.setIssueIds(Lists.newArrayList());
        //  Map 에 있는 데이터를 IssueVo 데이터로 변환한다.
        this.setMapToIssueVo(results, issueVos, issueCondition);
        User user = this.webAppUtil.getLoginUserObject();
        this.setMapToIssueVo(results, issueVos, issueCondition, user);
        this.setCountDownIssues(results, issueVos);
@@ -582,10 +597,10 @@
    }
    private void setCountDownIssues(List<Map<String, Object>> results, List<IssueVo> issueVos) {
        int downIssueCount = 0;
        for (Map<String, Object> result : results){
            List<Issue> downIssues = this.issueRepository.findByParentIssueId((Long) result.get("id")); //하위이슈 가져오기
            if(downIssues != null && downIssues.size() > 0){ //상위이슈 가지고 있는 애들이 있으면
                int downIssueCount = 0;
                for(Issue downIssue : downIssues){
                    downIssueCount ++;
                    Long parentIssueId = downIssue.getParentIssue().getId();
@@ -707,7 +722,9 @@
        IssueCondition issueCondition = new IssueCondition();
        //  검색 조건을 만든다
        if (!this.makeIssueSearchCondition(issueCondition, projectCondition, pageable)) {
        User user = this.webAppUtil.getLoginUserObject();
        if (!this.makeIssueSearchCondition(user, issueCondition, projectCondition, pageable)) {
            //  이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다.
            this.notFoundIssueList(resJsonData, pageable);
            return Lists.newArrayList();
@@ -751,7 +768,7 @@
    }
    //  Map 에 있는 데이터를 IssueVo 데이터로 변환한다.
    private void setMapToIssueVo(List<Map<String, Object>> results, List<IssueVo> issueVos, IssueCondition issueCondition) {
    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);
            issueVos.add(issueVo);
@@ -760,7 +777,7 @@
        //  이슈 사용자 정보 추가
        //this.setIssueUserList(issueVos, issueCondition);
        this.setIssueDepartmentList(issueVos, issueCondition);
        this.setIssueDepartmentList(issueVos, issueCondition, user);
        //  등록자 정보 추가
        this.setRegister(issueVos);  //  담당자 정보 셋팅
@@ -807,7 +824,7 @@
    }
    //  검색 조건을 만든다
    private boolean makeIssueSearchCondition(IssueCondition condition, ProjectCondition projectCondition, Pageable pageable) {
    private boolean makeIssueSearchCondition(User user, IssueCondition condition, ProjectCondition projectCondition, Pageable pageable) {
        if (pageable != null) {
            condition.setPage(pageable.getPageNumber() * pageable.getPageSize());
            condition.setPageSize(pageable.getPageSize());
@@ -825,7 +842,7 @@
        //  프로젝트를 선택하지 않았으면 해당 업무 공간에서 참여하고 있는 프로젝트를 찾는다.
        if (condition.getProjectIds().size() < 1) {
            List<Map<String, Object>> projects = null;
            if (this.userWorkspaceService.checkWorkspaceManager()) {
            if (this.userWorkspaceService.checkWorkspaceManager(user)) {
                projects = this.projectMapper.findByWorkspaceManagerAll(projectCondition);
            } else  {
                projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectCondition);
@@ -903,7 +920,7 @@
    }
    //  이슈 담당자 정보를 셋팅한다.
    private void setIssueUserList(List<IssueVo> issueVos, IssueCondition issueCondition) {
    private void setIssueUserList(List<IssueVo> issueVos, IssueCondition issueCondition, User user) {
        if (issueVos.size() < 1) {
            return;
        }
@@ -934,14 +951,14 @@
            }
            //  이슈 수정 권한을 갖고 있는지 확인
            if (this.checkHasPermission(issueVo, issueVo.getUserVos())) {
            if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user)) {
                issueVo.setModifyPermissionCheck(Boolean.TRUE);
            }
        }
    }
    //  이슈 담당부서 정보를 셋팅한다.
    private void setIssueDepartmentList(List<IssueVo> issueVos, IssueCondition issueCondition) {
    private void setIssueDepartmentList(List<IssueVo> issueVos, IssueCondition issueCondition, User user) {
        if (issueVos.size() < 1) {
            return;
        }
@@ -971,7 +988,7 @@
            }
            //  이슈 수정 권한을 갖고 있는지 확인
            if (this.checkHasPermission(issueVo, issueVo.getUserVos())) {
            if (this.checkHasPermission(issueVo, issueVo.getUserVos(), user)) {
                issueVo.setModifyPermissionCheck(Boolean.TRUE);
            }
        }
@@ -1021,9 +1038,25 @@
    // 하위 이슈 정보를 셋팅한다
    private void setDownIssues(Issue issue, IssueVo issueVo) {
        List<Issue> downIssues = this.issueRepository.findByParentIssueId(issue.getId());
        /*if(issueVo != null && downIssues.size()>0){
            for(Issue downIssue : downIssues){
                IssueVo downIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class);
                IssueDownVo issueDownVo = ConvertUtil.copyProperties(downIssueVo, IssueDownVo.class);
                issueDownVo.setIssueDown(downIssueVo);
                issueDownVo.setTitle(downIssue.getTitle());
                issueDownVo.setIssueTypeVo(ConvertUtil.copyProperties(downIssue.getIssueType(), IssueTypeVo.class));
                issueDownVo.setPriorityVo(ConvertUtil.copyProperties(downIssue.getPriority(), PriorityVo.class));
                issueDownVo.setSeverityVo(ConvertUtil.copyProperties(downIssue.getSeverity(), SeverityVo.class));
                this.setRegister(downIssue, downIssueVo); // 등록자
                this.setIssueDepartment(downIssue, downIssueVo);  //  담당부서 정보 셋팅
                this.setIssueCustomFields(downIssue, downIssueVo);   // 사용자정의필드 정보 세팅
                issueVo.addIssueDownVo(issueDownVo);
            }
        }*/
        List<IssueVo> downIssueVos = ConvertUtil.convertObjectsToClasses(downIssues, IssueVo.class);
        List<IssueVo> resultList = new ArrayList<>();
        if(downIssues != null && downIssueVos.size()>0){
        if(downIssueVos != null && downIssueVos.size()>0){
            for(IssueVo downIssueVo : downIssueVos){
                for(Issue downIssue : downIssues){
                    downIssueVo.setIssueTypeVo(ConvertUtil.copyProperties(downIssue.getIssueType(), IssueTypeVo.class));
@@ -1035,9 +1068,7 @@
                }
                resultList.add(downIssueVo);
            }
            issueVo.setIssueDownVos(resultList); //프론트에서 List형태로 받아줘서 리스트 형식으로 보내줌
        }else{
            issueVo.setIssueDownVos(null);
            issueVo.setIssueDownVos(resultList);
        }
    }
@@ -1225,13 +1256,42 @@
        issueVo.setIssueHistoryVos(this.issueHistoryService.findIssueHistory(issue.getId()));
    }
    // 이슈를 수정한다
    // 사용자 정의 필드 값이 같은 이슈 찾기
    @Override
    public Issue modifyIssue(IssueApiForm issueApiForm, List<MultipartFile> files) {
    @Transactional
    public List<IssueVo> findIssue(IssueApiForm issueApiform) {
        List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
        IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
        if (issueCustomFieldValueForms != null && issueCustomFieldValueForms.size() > 0) {
            for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
                issueCustomFieldValueCondition.addUseValues(issueCustomFieldValueForm.getUseValue());
            }
        }
        List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
        List<IssueVo> issueVos = Lists.newArrayList();
        if (results != null && results.size() > 0) {
            issueVos.add(ConvertUtil.convertMapToClass(results.get(0), IssueVo.class));
        }
        return issueVos;
    }
    // 이슈를 수정한다(api용)
    @Override
    @Transactional
    public List<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);
        List<IssueVo> issueVos = this.findIssue(issueApiForm);
        List<Issue> issue = Lists.newArrayList();
        for (IssueVo issueVo : issueVos) {
            issueForm.setId(issueVo.getId());
            issue.add(this.modifyIssueForApi(user, issueForm, files));
        }
        return issue;
    }
    //  이슈를 수정한다.
@@ -1242,14 +1302,16 @@
        return modifyIssue(user, issueForm, multipartFiles);
    }
    //  이슈를 수정한다.
    @Override
    @Transactional
    public Issue modifyIssue(User user, IssueForm issueForm, List<MultipartFile> 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(issueForm.getId());
        this.verifyIssueModifyPermission(issue, user);
        //  프로젝트 유효성 체크
        Project project = this.projectService.getProject(issueForm.getProjectId());
        //  이슈 상태 유효성 체크
@@ -1270,10 +1332,83 @@
        //  담당부서 유효성 체크
        this.verifyIssueDepartment(project, issueForm);
        Issue issue = this.getIssue(issueForm.getId());
        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);
        Issue issue = checkIssueData.getIssue();
        Project project = checkIssueData.getProject();
        IssueType issueType = checkIssueData.getIssueType();
        IssueStatus oldIssueStatus = checkIssueData.getOldIssueStatus();
        IssueStatus issueStatus = checkIssueData.getNewIssueStatus();
        //  변경 이력 정보 추출
        StringBuilder detectIssueChange = this.issueHistoryService.detectIssueChange(issue, issueForm, project, issueStatus, issueType, priority, severity, multipartFiles);
        StringBuilder detectIssueChange = this.issueHistoryService.detectIssueChange(issueForm, checkIssueData, multipartFiles);
        //  프로젝트가 변경되면 이슈 넘버를 새로 따야 한다.
        this.checkChangeProject(checkIssueData.getProject(), 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);
        //  이슈 이력 등록
        if (!StringUtils.isEmpty(detectIssueChange.toString())) {
            this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString());
        }
        //  사용자 시스템 기능 사용 정보 수집
        UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class);
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_MODIFY));
        return issue;
    }
    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);
@@ -1283,19 +1418,10 @@
            issueStatus = this.issueStatusService.findByIssueStatusTypeIsReady(issueType.getWorkflow());
            //  이슈 상태 변경 이력 남기기 - 이력을 남기기 위해 issueForm 에 issueStatus Id 값을 저장.
            issueForm.setIssueStatusId(issueStatus.getId());
            this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, issueStatus);
            this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, oldIssueStatus, issueStatus);
        }
        ConvertUtil.copyProperties(issueForm, issue, "id");
        issue.setProject(project);
        issue.setIssueStatus(issueStatus);
        issue.setIssueType(issueType);
        issue.setPriority(priority);
        issue.setSeverity(severity);
        issue.setStartDate(issueForm.getStartDate());
        issue.setCompleteDate(issueForm.getCompleteDate());
        this.issueRepository.saveAndFlush(issue);
        issue = this.saveIssue(issueForm, checkIssueData);
        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
        //  담당부서 지정
        if(issueForm.getDepartmentIds().size()>0){
@@ -1318,7 +1444,8 @@
            this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.MODIFY, detectIssueChange.toString());
        }
        //  사용자 시스템 기능 사용 정보 수집
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_MODIFY));
        UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class);
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_MODIFY));
        //  업체 정보 저장
        this.issueCompanyService.modifyIssueCompanyField(issue, issueForm.getIssueCompanyFields());
@@ -1440,11 +1567,9 @@
    }
    //  이슈 수정 권한 체크
    private void verifyIssueModifyPermission(Long issueId) {
        Issue issue = this.getIssue(issueId);
    private void verifyIssueModifyPermission(Issue issue, User user) {
        //  이슈 수정 권한을 갖고 있는지 확인
        if (!this.checkHasPermission(ConvertUtil.copyProperties(issue, IssueVo.class), this.getIssueUserVos(issue))) {
        if (!this.checkHasPermission(ConvertUtil.copyProperties(issue, IssueVo.class), this.getIssueUserVos(issue), user)) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_MODIFY_PERMISSION));
        }
@@ -1454,24 +1579,31 @@
    private List<UserVo> getIssueUserVos(Issue issue) {
        List<UserVo> userVos = Lists.newArrayList();
        for (IssueUser issueUser : issue.getIssueUsers()) {
            UserVo userVo = ConvertUtil.copyProperties(issueUser.getUser(), UserVo.class, "password");
            userVos.add(userVo);
        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 boolean checkHasPermission(IssueVo issueVo, List<UserVo> issueUserVos) {
    private boolean checkHasPermission(IssueVo issueVo, List<UserVo> issueUserVos, User user) {
        boolean hasPermission = false;
        //  업무 공간 관리자일 경우 수정 권한을 갖는다.
        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.WORKSPACE_MANAGER, issueVo, null, null);
        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.WORKSPACE_MANAGER, issueVo, null, null, user);
        //  프로젝트 관리자일 경우 해당 프로젝트에 등록된 이슈는 수정 권한을 갖는다.
        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.PROJECT_MANAGER, issueVo, null, null);
        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.PROJECT_MANAGER, issueVo, null, null, user);
        //   이슈 등록자일 경우 수정 권한을 갖는다.
        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.REGISTER, issueVo, null, null);
        hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.REGISTER, issueVo, null, null, user);
        //  이슈 담당자일 경우 수정 권한을 갖는다. => 담당부서로 수정 - 체크
        //hasPermission = this.checkIssueModifyPermission(hasPermission, Issue.ASSIGNEE, issueVo, issueUserVos);
        //  담당자가 없으면 모든 사용자가 수정 권한을 갖는다.
@@ -1480,22 +1612,22 @@
    }
    //  이슈 수정 권한을 확인한다.
    private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List<UserVo> issueUserVos, List<DepartmentVo> issueDepartmentVos) {
    private boolean checkIssueModifyPermission(Boolean hasPermission, String checkType, IssueVo issueVo, List<UserVo> issueUserVos, List<DepartmentVo> issueDepartmentVos, User user) {
        if (!hasPermission) {
            switch (checkType) {
                case Issue.WORKSPACE_MANAGER:  //  업무 공간 관리자
                    //  업무 공간 관리자일 경우 수정 권한을 갖는다.
                    hasPermission = this.userWorkspaceService.checkWorkspaceManager();
                    hasPermission = this.userWorkspaceService.checkWorkspaceManager(user);
                    break;
                case Issue.PROJECT_MANAGER:    //  프로젝트 관리자
                    Issue issue = this.getIssue(issueVo.getId());
                    //  프로젝트 관리자일 경우 해당 프로젝트에 등록된 이슈는 수정 권한을 갖는다.
                    hasPermission = this.projectRoleUserService.checkProjectManager(issue.getProject());
                    hasPermission = this.projectRoleUserService.checkProjectManager(issue.getProject(), user);
                    break;
                case Issue.REGISTER:   //  이슈 등록자
                    hasPermission = issueVo.getRegisterId().equals(this.webAppUtil.getLoginId());
                    hasPermission = issueVo.getRegisterId().equals(user.getId());
                    break;
                case Issue.ASSIGNEE:
@@ -1506,7 +1638,7 @@
                    }
                    //   이슈 담당자 여부 확인
                    for (UserVo issueUserVo : issueUserVos) {
                        if (issueUserVo.getId().equals(this.webAppUtil.getLoginId())) {
                        if (issueUserVo.getId().equals(user.getId())) {
                            hasPermission = true;
                            break;
                        }
@@ -1536,20 +1668,22 @@
    //  이슈 상태 변경
    @Override
    @Transactional
    public void modifyIssueStatus(IssueForm issueForm) {
    public void modifyIssueStatus(IssueForm issueForm, User user) {
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
        //  변경 이력 정보 추출
        StringBuilder detectIssueChange = new StringBuilder();
        //  이슈 수정 권한 체크
        this.verifyIssueModifyPermission(issueForm.getId());
        Issue issue = this.getIssue(issueForm.getId());
        IssueStatus oldIssueStatus = issue.getIssueStatus();
        this.verifyIssueModifyPermission(issue, user);
        IssueStatus issueStatus = this.issueStatusService.getIssueStatus(issueForm.getIssueStatusId());
        //  이슈 상태를 변경할 때 선택한 이슈 상태로 변경할 수 있는지 확인한다.
        this.issueStatusService.checkNextIssueStatus(issue, issueStatus);
        //  변경 이력 정보 추출
        this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, issueStatus);
        this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, oldIssueStatus, issueStatus);
        issue.setIssueStatus(issueStatus);
        this.issueRepository.saveAndFlush(issue);
@@ -1583,13 +1717,15 @@
    @Override
    @Transactional
    public void modifyIssueUser(IssueForm issueForm) {
        User user = this.webAppUtil.getLoginUserObject();
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
        //  변경 이력 정보 추출
        StringBuilder detectIssueChange = new StringBuilder();
        //  이슈 수정 권한 체크
        this.verifyIssueModifyPermission(issueForm.getId());
        Issue issue = this.getIssue(issueForm.getId());
        this.verifyIssueModifyPermission(issue, user);
        issue.setProject(this.projectService.getProject(issueForm.getProjectId()));
        //  변경 이력 정보 추출
@@ -1618,13 +1754,14 @@
    @Override
    @Transactional
    public void modifyIssueDepartment(IssueForm issueForm) {
        User user = this.webAppUtil.getLoginUserObject();
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
        //  변경 이력 정보 추출
        StringBuilder detectIssueChange = new StringBuilder();
        //  이슈 수정 권한 체크
        this.verifyIssueModifyPermission(issueForm.getId());
        Issue issue = this.getIssue(issueForm.getId());
        this.verifyIssueModifyPermission(issue, user);
        issue.setProject(this.projectService.getProject(issueForm.getProjectId()));
        //  변경 이력 정보 추출
@@ -1656,6 +1793,7 @@
    @Transactional
    public void removeIssues(IssueForm issueForm) {
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        User user = this.webAppUtil.getLoginUserObject();
        this.workspaceService.checkUseWorkspace();
        if (issueForm.getRemoveIds().size() < 1) {
@@ -1666,7 +1804,7 @@
        List<Issue> removeIssues = Lists.newArrayList();
        for (Long issueId : issueForm.getRemoveIds()) {
            Issue issue = this.issueRemoves(issueId);
            Issue issue = this.issueRemoves(issueId, user);
            removeIssues.add(issue);
        }
@@ -1678,10 +1816,10 @@
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_REMOVE));
    }
    private Issue issueRemoves(Long issueId) {
    private Issue issueRemoves(Long issueId, User user) {
        Issue issue = this.getIssue(issueId);
        //  이슈 수정 권한을 갖고 있는지 확인
        this.verifyIssueModifyPermission(issueId);
        this.verifyIssueModifyPermission(issue, user);
        //  이슈 첨부 파일을 삭제한다.
        if (issue.getAttachedFiles().size() > 0) {
@@ -1845,7 +1983,8 @@
        issueCondition.setIssueIds(Lists.newArrayList());
        //  Map 에 있는 데이터를 IssueVo 데이터로 변환한다.
        this.setMapToIssueVo(results, issueVos, issueCondition);
        User user = this.webAppUtil.getLoginUserObject();
        this.setMapToIssueVo(results, issueVos, issueCondition, user);
        //  IssueVos 데이터를 엑셀에서 표시할 수 있는 데이터로 변경한다.
        List<Map<String, String>> convertExcelViewToIssueMaps = this.convertExcelViewToIssueVos(issueVos);
@@ -2013,10 +2152,12 @@
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
        User user = this.webAppUtil.getLoginUserObject();
        for (Long issueId : issueForm.getIds()) {
            issueForm.setId(issueId);
            //  이슈 상태 변경
            this.modifyIssueStatus(issueForm);
            this.modifyIssueStatus(issueForm, user);
        }
        // 담당 부서 수정
@@ -2942,7 +3083,7 @@
        StringBuilder sb = new StringBuilder();
        Issue parentIssue = issue.getParentIssue(); //변경 전 하위이슈의 상위이슈
        if(parentIssue != null){ //변경 전 하위이슈의 상위이슈가 존재 할 경우
        if(parentIssue != null && parentIssue.getId().equals(newParentIssueId)){ //변경 전 하위이슈의 상위이슈가 존재 할 경우
            this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
            this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString());
        }
@@ -2951,7 +3092,7 @@
            parentIssue = this.getIssue(newParentIssueId); //상위이슈(myIssue)
            issue.setParentIssue(parentIssue); //myIssue를 하위이슈의 상위이슈로 set
            this.issueHistoryService.detectDownIssues(IssueHistoryType.ADD, issue, sb); //issue = 하위이슈
        } else  {
        } else{
            // 삭제 할 경우
            this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
            issue.setParentIssue(null);
src/main/java/kr/wisestone/owl/service/impl/ProjectRoleUserServiceImpl.java
@@ -137,10 +137,10 @@
    //  프로젝트 관리자 여부를 확인한다.
    @Override
    @Transactional(readOnly = true)
    public boolean checkProjectManager(Project project) {
    public boolean checkProjectManager(Project project, User user) {
        ProjectRole projectManagerRole = this.projectRoleService.findByProjectIdAndRoleType(project.getId(), ProjectRole.TYPE_MANAGER);
        //  해당 사용자가 특정 역할에 소속되어 있는지 확인한다.
        ProjectRoleUser projectRoleUser = this.findByProjectRoleIdAndUserId(projectManagerRole.getId(), this.webAppUtil.getLoginId());
        ProjectRoleUser projectRoleUser = this.findByProjectRoleIdAndUserId(projectManagerRole.getId(), user.getId());
        return projectRoleUser != null;
    }
src/main/java/kr/wisestone/owl/service/impl/ProjectServiceImpl.java
@@ -342,10 +342,12 @@
        List<Map<String, Object>> results;
        Long totalCount;
        User user = this.webAppUtil.getLoginUserObject();
        if (condition.getWorkspaceManager()) {
            //  업무공간 관리자일 경우 모든 프로젝트가 표시되어야 한다.
            //  관리자일 때
            if (this.userWorkspaceService.checkWorkspaceManager()) {
            if (this.userWorkspaceService.checkWorkspaceManager(user)) {
                results = this.projectMapper.findByWorkspaceManager(condition);
                totalCount = this.projectMapper.countByWorkspaceManager(condition);
            }
@@ -361,8 +363,8 @@
        int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1;
        //  프로젝트 조회 결과를 ProjectVos 로 변환한다. - 관리자, 일반 사용자 정보 추가
        List<ProjectVo> projectVos = this.makeProjectVos(results);
        this.setChildrenProject(projectVos);
        List<ProjectVo> projectVos = this.makeProjectVos(results, user);
        this.setChildrenProject(projectVos, user);
        resJsonData.put(Constants.RES_KEY_CONTENTS, projectVos);
        resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(),
@@ -371,16 +373,16 @@
        return projectVos;
    }
    void setChildrenProject(List<ProjectVo> projectVos) {
    void setChildrenProject(List<ProjectVo> projectVos, User user) {
        int projectCount = projectVos.size();
        for (int i=0; i< projectCount; i++) {
            ProjectVo projectVo = projectVos.get(i);
            List<Map<String, Object>> children = this.projectMapper.findChildrenProject(projectVo.getId());
            if (children != null && children.size() > 0) {
                List<ProjectVo> childrenVo = this.makeProjectVos(children);
                List<ProjectVo> childrenVo = this.makeProjectVos(children, user);
                projectVo.setChildProjects(childrenVo);
                setChildrenProject(childrenVo);
                setChildrenProject(childrenVo, user);
            }
        }
    }
@@ -400,7 +402,7 @@
    //  프로젝트 조회 결과를 ProjectVos 로 변환한다. - 관리자, 일반 사용자 정보 추가
    private List<ProjectVo> makeProjectVos(List<Map<String, Object>> results) {
    private List<ProjectVo> makeProjectVos(List<Map<String, Object>> results, User user) {
        List<ProjectVo> projectVos = Lists.newArrayList();
        for (Map<String, Object> result : results) {
@@ -413,7 +415,7 @@
            this.setProjectDepartment(projectVo);
            //  업무공간 담당자는 모든 프로젝트를 수정/삭제할 수 있어야 한다.
            if (this.userWorkspaceService.checkWorkspaceManager()) {
            if (this.userWorkspaceService.checkWorkspaceManager(user)) {
                projectVo.setModifyPermissionCheck(true);
            }
            projectVos.add(projectVo);
@@ -532,10 +534,12 @@
        //  프로젝트 참여 부서
        List<Long> existDepartmentIds = this.getIncludeProjectDepartment(project);
        User user = this.webAppUtil.getLoginUserObject();
        //  워크스페이스에서 기본으로 제공되는 프로젝트에 대한 체크
        this.checkDefaultProject(project, projectForm);
        //  수정 권한 체크
        this.checkModifyPermission(project.getId());
        this.checkModifyPermission(project.getId(), user);
        //  관리자 변경
        Map<String, Object> changeProjectManagerNotifications = this.modifyProjectManagers(project, projectForm, ProjectRole.TYPE_MANAGER);
        //  일반 사용자 변경
@@ -659,11 +663,11 @@
    }
    //  로그인한 사용자가 관리자 역할에 소속되어 있는지 확인한다.
    private void checkModifyPermission(Long projectId) {
    private void checkModifyPermission(Long projectId, User user) {
        Boolean hasPermission = Boolean.FALSE;
        //  해당 업무 공간의 관리자일 경우 권한 체크를 하지 않는다.
        if (this.userWorkspaceService.checkWorkspaceManager()) {
        if (this.userWorkspaceService.checkWorkspaceManager(user)) {
            return;
        }
@@ -1000,7 +1004,7 @@
        }
        //  로그인한 사용자가 관리자 역할에 소속되어 있는지 확인한다.
        this.checkModifyPermission(project.getId());
        this.checkModifyPermission(project.getId(), this.webAppUtil.getLoginUserObject());
        List<String> sendEmails = Lists.newArrayList();
        Map<String, Object> params = new HashMap<>();
@@ -1094,21 +1098,23 @@
    @Override
    @Transactional(readOnly = true)
    public List<ProjectVo> findByIncludeProject(List<String> statuses, String projectType) {
        User user = this.webAppUtil.getLoginUserObject();
        ProjectCondition projectCondition = new ProjectCondition();
        projectCondition.setLoginUserId(this.webAppUtil.getLoginId());
        projectCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
        projectCondition.setLoginUserId(user.getId());
        projectCondition.setWorkspaceId(user.getLastWorkspaceId());
        projectCondition.setProjectType(projectType);
        projectCondition.setStatuses(statuses);
        List<Map<String, Object>> results;
        if (this.userWorkspaceService.checkWorkspaceManager()) {
        if (this.userWorkspaceService.checkWorkspaceManager(user)) {
            results = this.projectMapper.findByWorkspaceManager(projectCondition);
        } else {
            results = this.projectMapper.findByWorkspaceIdAndIncludeProject(projectCondition);
        }
        List<ProjectVo> projectVos = this.makeProjectByVos(results);
        this.setChildrenProject(projectVos);
        this.setChildrenProject(projectVos, user);
        return  projectVos;
    }
@@ -1135,7 +1141,7 @@
        projectCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
        List<Map<String, Object>> results = this.projectMapper.find(projectCondition);
        //  프로젝트 조회 결과를 ProjectVos 로 변환한다. - 관리자, 일반 사용자 정보 추가
        List<ProjectVo> projectVos = this.makeProjectVos(results);
        List<ProjectVo> projectVos = this.makeProjectVos(results, this.webAppUtil.getLoginUserObject());
        ExportExcelVo excelInfo = new ExportExcelVo();
        excelInfo.setFileName(this.messageAccessor.message("common.projectList")); // 프로젝트 목록
        excelInfo.addAttrInfos(new ExportExcelAttrVo("statusName", this.messageAccessor.message("common.status"), 6, ExportExcelAttrVo.ALIGN_CENTER)); // 상태
src/main/java/kr/wisestone/owl/service/impl/UserWorkspaceServiceImpl.java
@@ -238,15 +238,14 @@
    //  업무 공간 담당자 여부를 확인한다.
    @Override
    @Transactional(readOnly = true)
    public boolean checkWorkspaceManager() {
    public boolean checkWorkspaceManager(User user) {
        boolean bIsManager = false;
        User loginUser = this.userService.getUser(this.webAppUtil.getLoginId());
        try
        {
            Workspace workspace = this.workspaceService.getWorkspace(loginUser.getLastWorkspaceId());   //  현재 접속한 업무 공간
            Workspace workspace = this.workspaceService.getWorkspace(user.getLastWorkspaceId());   //  현재 접속한 업무 공간
            //  로그인한 사용자가 관리하는 업무 공간을 찾는다.
            UserWorkspace userWorkspace = this.findMyWorkspace(this.webAppUtil.getLoginId());
            UserWorkspace userWorkspace = this.findMyWorkspace(user.getId());
            bIsManager = workspace.getId().equals(userWorkspace.getWorkspace().getId());
        }
src/main/java/kr/wisestone/owl/service/impl/WidgetServiceImpl.java
@@ -5,10 +5,7 @@
import kr.wisestone.owl.common.MessageAccessor;
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.domain.IssueStatus;
import kr.wisestone.owl.domain.Project;
import kr.wisestone.owl.domain.ProjectClosure;
import kr.wisestone.owl.domain.UserDepartment;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.domain.enumType.ProjectType;
import kr.wisestone.owl.exception.OwlRuntimeException;
import kr.wisestone.owl.mapper.IssueMapper;
@@ -166,9 +163,10 @@
    @Override
    @Transactional(readOnly = true)
    public WidgetCondition makeWidgetCondition() {
        User user = this.webAppUtil.getLoginUserObject();
        //  해당 워크스페이스에서 참여하고 있는 프로젝트 중 상태가 오픈인 프로젝트
        List<Map<String, Object>> projects = null;
        if (this.userWorkspaceService.checkWorkspaceManager()) {
        if (this.userWorkspaceService.checkWorkspaceManager(user)) {
            projects = this.projectService.findByWorkspaceManagerAll();
        } else  {
            projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(Lists.newArrayList("02"), ProjectType.BTS_PROJECT.toString());
@@ -277,9 +275,11 @@
    public void findProjectProgress(Map<String, Object> resJsonData, WidgetCondition widgetCondition) {
        List<Map<String, Object>> progressingProjectDetails = Lists.newArrayList();
        User user = this.webAppUtil.getLoginUserObject();
        if (widgetCondition.getProjectIds().size() > 0) {
            SetMeAndDownProjectIds(widgetCondition.getProjectIds(), widgetCondition);
            if (this.userWorkspaceService.checkWorkspaceManager()) {
            if (this.userWorkspaceService.checkWorkspaceManager(user)) {
                progressingProjectDetails = this.widgetMapper.findProjectProgressAll(widgetCondition);
            } else {
                progressingProjectDetails = this.widgetMapper.findProjectProgress(widgetCondition);
src/main/java/kr/wisestone/owl/vo/IssueDownVo.java
New file
@@ -0,0 +1,93 @@
package kr.wisestone.owl.vo;
import com.google.common.collect.Lists;
import java.util.List;
public class IssueDownVo extends BaseVo {
    private Long id;
    private IssueVo issue;
    private IssueVo issueDown;
    private String title;
    private IssueTypeVo issueTypeVo;    //  이슈 상세에서 사용
    private PriorityVo priorityVo;  //  이슈 상세에서 사용
    private SeverityVo severityVo;  //  이슈 상세에서 사용
    private UserVo registerVo;  //  이슈 상세에서 사용
    private List<DepartmentVo> departmentVos = Lists.newArrayList(); //담당부서
    private Boolean modifyPermissionCheck = Boolean.FALSE;
    public IssueDownVo() {}
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public IssueVo getIssue() { return issue; }
    public void setIssue(IssueVo issue) { this.issue = issue; }
    public IssueVo getIssueDown() {
        return issueDown;
    }
    public void setIssueDown(IssueVo issueDown) {
        this.issueDown = issueDown;
    }
    public String getTitle() { return  this.title; }
    public void setTitle(String title) { this.title = title; }
    public IssueTypeVo getIssueTypeVo() {
        return issueTypeVo;
    }
    public void setIssueTypeVo(IssueTypeVo issueTypeVo) {
        this.issueTypeVo = issueTypeVo;
    }
    public PriorityVo getPriorityVo() {
        return priorityVo;
    }
    public void setPriorityVo(PriorityVo priorityVo) {
        this.priorityVo = priorityVo;
    }
    public SeverityVo getSeverityVo() {
        return severityVo;
    }
    public void setSeverityVo(SeverityVo severityVo) {
        this.severityVo = severityVo;
    }
    public UserVo getRegisterVo() {
        return registerVo;
    }
    public void setRegisterVo(UserVo registerVo) {
        this.registerVo = registerVo;
    }
    public List<DepartmentVo> getDepartmentVos() {
        return departmentVos;
    }
    public void setDepartmentVos(List<DepartmentVo> departmentVos) {
        this.departmentVos = departmentVos;
    }
    public Boolean getModifyPermissionCheck() {
        return modifyPermissionCheck;
    }
    public void setModifyPermissionCheck(Boolean modifyPermissionCheck) {
        this.modifyPermissionCheck = modifyPermissionCheck;
    }
}
src/main/java/kr/wisestone/owl/vo/IssueVo.java
@@ -45,6 +45,7 @@
    private List<IssueTypeCustomFieldVo> issueTypeCustomFieldVos = Lists.newArrayList();
    private List<IssueCustomFieldValueVo> issueCustomFieldValueVos = Lists.newArrayList();
    private List<IssueRelationVo> issueRelations = Lists.newArrayList();
    //private List<IssueDownVo> issueDownVos = Lists.newArrayList();
    private List<IssueVo> issueDownVos = Lists.newArrayList();
    private List<IssueVo> issueRelationVos = Lists.newArrayList();
    private Long attachedFileCount;
@@ -402,6 +403,14 @@
        this.issueRelations.add(issueRelationVo);
    }
    /*public void addIssueDownVo(IssueDownVo issueDownVo) {
        if (this.issueDownVos == null){
            this.issueDownVos = new ArrayList<>();
        }
        this.issueDownVos.add(issueDownVo);
    }*/
    public  List<IssueVo> getIssueRelationIssueVos() { return  this.issueRelationVos; }
    public void setIssueRelationIssueVos(List<IssueVo> issueRelationVos) { this.issueRelationVos = issueRelationVos; }
@@ -414,6 +423,14 @@
        this.departmentVos = departmentVos;
    }
    /*public List<IssueDownVo> getIssueDownVos() {
        return issueDownVos;
    }
    public void setIssueDownVos(List<IssueDownVo> issueDownVos) {
        this.issueDownVos = issueDownVos;
    }*/
    public List<IssueVo> getIssueDownVos() {
        return issueDownVos;
    }
src/main/java/kr/wisestone/owl/web/form/IssueApiForm.java
@@ -23,6 +23,7 @@
    private String projectKey;
    private String description;
    private Long issueTypeId;
    private Long issueStatusId;
    private Long priorityId;
    private Long severityId;
    private Date startDate;
@@ -217,4 +218,12 @@
    public void setMultipartFiles(List<MultipartFile> multipartFiles) {
        this.multipartFiles = multipartFiles;
    }
    public Long getIssueStatusId() {
        return issueStatusId;
    }
    public void setIssueStatusId(Long issueStatusId) {
        this.issueStatusId = issueStatusId;
    }
}
src/main/java/kr/wisestone/owl/web/form/IssueForm.java
@@ -229,6 +229,12 @@
        this.departmentIds = departmentIds;
    }
    public void addDepartmentId(Long departmentId) {
        if (this.departmentIds != null) {
            this.departmentIds.add(departmentId);
        }
    }
    public List<Long> getRemoveFiles() {
        return removeFiles;
    }
src/main/resources/system_prod.properties
@@ -40,8 +40,8 @@
# email \uC124\uC815
email.host=mail.g2works.kr
email.port=587
email.userName=wyu@maprex.co.kr
email.password=1234
email.userName=supportowl@wisestone.kr
email.password=Stone0620**
email.transport.protocol=smtp
email.smtp.auth=true
email.smtp.starttle.enable=true
src/main/webapp/scripts/app/issue/issueDetail.controller.js
@@ -870,7 +870,8 @@
                                // 하위 이슈 반목문
                                if (result.data.data.issueDownVos !== null){
                                    angular.forEach(result.data.data.issueDownVos, function (issueDownVo){
                                        $scope.vm.form.issuesDown.push(issueDownVo.issue);
                                        //$scope.vm.form.issuesDown.push(issueDownVo.issueDown);
                                        $scope.vm.form.issuesDown.push(issueDownVo);
                                    });
                                }
                                $scope.vm.viewer.issueRelationVos = result.data.data.issueRelationVos;