OWL ITS + 탐지시스템(인터넷 진흥원)
wyu
2021-12-05 43a8e9281c71f21b0e683e63def386d1ec0209bd
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);