OWL ITS + 탐지시스템(인터넷 진흥원)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
package kr.wisestone.owl.service.impl;
 
import com.google.common.collect.Lists;
import kr.wisestone.owl.common.ExcelConditionCheck;
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.domain.*;
import kr.wisestone.owl.domain.enumType.ProjectType;
import kr.wisestone.owl.exception.OwlRuntimeException;
import kr.wisestone.owl.mapper.WorkflowMapper;
import kr.wisestone.owl.repository.WorkflowRepository;
import kr.wisestone.owl.service.*;
import kr.wisestone.owl.util.ConvertUtil;
import kr.wisestone.owl.vo.*;
import kr.wisestone.owl.web.condition.WorkflowCondition;
import kr.wisestone.owl.web.condition.WorkflowDepartmentCondition;
import kr.wisestone.owl.web.form.WorkflowForm;
import kr.wisestone.owl.web.view.ExcelView;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
 
@Service
public class WorkflowServiceImpl extends AbstractServiceImpl<Workflow, Long, JpaRepository<Workflow, Long>>
        implements WorkflowService {
 
    private static final Logger log = LoggerFactory.getLogger(WorkflowServiceImpl.class);
 
    @Autowired
    private WorkflowRepository workflowRepository;
 
    @Autowired
    private IssueStatusService issueStatusService;
 
    @Autowired
    private WorkflowTransitionService workflowTransitionService;
 
    @Autowired
    private WorkflowDepartmentService workflowDepartmentService;
 
    @Autowired
    private WorkspaceService workspaceService;
 
    @Autowired
    private IssueService issueService;
 
    @Autowired
    private UserService userService;
 
    @Autowired
    private WorkflowMapper workflowMapper;
 
    @Autowired
    private ExcelView excelView;
 
    @Autowired
    private ExcelConditionCheck excelConditionCheck;
 
    @Override
    protected JpaRepository<Workflow, Long> getRepository() {
        return this.workflowRepository;
    }
 
    //  기본 프로젝트에서 사용되는 기본 워크플로우
    @Override
    @Transactional
    public void addDefaultWorkflow(Workspace workspace, List<ProjectType> projectTypes) {
 
        for (ProjectType projectType : projectTypes) {
            List<IssueStatus> issueStatuses = Lists.newArrayList();
            //  워크플로우 생성
            Workflow workflow = new Workflow();
            workflow.setWorkspace(workspace);
            workflow.setProjectType(projectType);   //  project 생성시 project type 에 맞는 워크플로우/이슈 유형을 자동 생성할 수 있게 해준다. - 프로젝트 템플릿 유형 별로 해당 project type 에 맞는 워크플로우로 생성해준다.
 
            switch(projectType) {
                case BTS_PROJECT:
                    workflow.setName(this.messageAccessor.message("common.btsWorkflow")); // BTS 워크플로우
                    workflow.setDescription(this.messageAccessor.message("common.usedToManageThisWorkflow")); // 버그를 관리하는데 사용하는 워크플로우 입니다.
                    issueStatuses = this.issueStatusService.findByWorkspaceId(workspace.getId());
                    break;
                case RMS_PROJECT:
                    workflow.setName(this.messageAccessor.message("common.rmsWorkflow")); // RMS 워크플로우
                    workflow.setDescription(this.messageAccessor.message("common.userToManageRequirementsThisWorkflow")); // 요구 사항을 관리하는데 사용하는 워크플로우 입니다.
                    issueStatuses = this.issueStatusService.findByWorkspaceId(workspace.getId());
                    break;
                case TCM_PROJECT:
                    workflow.setName(this.messageAccessor.message("common.tcmWorkflow")); // TCM 워크플로우
                    workflow.setDescription(this.messageAccessor.message("common.userToManageTestCasesThisWorkflow")); // 테스트 케이스를 관리하는데 사용하는 워크플로우 입니다.
                    issueStatuses = this.issueStatusService.findByWorkspaceId(workspace.getId());
                    break;
            }
 
            //  워크스페이스에 기본 제공되는 이슈 상태가 없을 경우에는 오류
            if (issueStatuses.isEmpty()) {
                throw new OwlRuntimeException(
                        this.messageAccessor.getMessage(MsgConstants.ISSUE_STATUS_NOT_EXIST));
            }
 
            this.workflowRepository.saveAndFlush(workflow);
            //  워크플로우 전이 연결.
            this.workflowTransitionService.addDefaultWorkflowTransition(workflow, issueStatuses, projectType);
        }
    }
 
    //  워크플로우를 생성한다.
    @Override
    @Transactional
    public Workflow addWorkflow(WorkflowForm workflowForm) {
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
 
        //  이름 유효성 체크
        this.verifyName(workflowForm.getName(), null);
        Workflow workflow = ConvertUtil.copyProperties(workflowForm, Workflow.class, "projectType");
        Workspace workspace = this.workspaceService.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
        workflow.setWorkspace(workspace);
 
        workflow = this.workflowRepository.saveAndFlush(workflow);
        this.workflowTransitionService.modify(workflow, workflowForm.getIssueStatusVos());
        this.workflowDepartmentService.modify(workflow, workflowForm.getIssueStatusVos());
 
        return workflow;
    }
 
    //  이름 유효성 체크
    private void verifyName(String name, Long id) {
        if (StringUtils.isEmpty(name)) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_NOT_NAME));
        }
 
        if (name.length() > 20) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_NAME_MAX_LENGTH_OUT));
        }
 
        Workflow workflow;
        Long workspaceId = this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId();
 
        if (id == null) {
            workflow = this.workflowRepository.findByNameAndWorkspaceId(name, workspaceId);
        }
        else {
            workflow = this.workflowRepository.findByNameAndWorkspaceIdAndIdNot(name, workspaceId, id);
        }
 
        if (workflow != null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_USED_NAME));
        }
    }
 
    //  워크플로우 목록을 조회한다.
    @Override
    @Transactional(readOnly = true)
    public List<WorkflowVo> findWorkflow(Map<String, Object> resJsonData,
                                  WorkflowCondition condition, Pageable pageable) {
 
        condition.setPage(pageable.getPageNumber() * pageable.getPageSize());
        condition.setPageSize(pageable.getPageSize());
        condition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
        List<Map<String, Object>> results = this.workflowMapper.find(condition);
        Long totalCount = this.workflowMapper.count(condition);
        int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1;
        List<WorkflowVo> workflowVos = ConvertUtil.convertListToListClass(results, WorkflowVo.class); //workflow 리스트
        //  워크플로우를 사용하는 이슈 유형 정보를 추가한다.
        this.setIssueTypeVos(workflowVos);
        //  워크플로우 담당부서 정보를 추가한다.
        this.setDepartmentVos(workflowVos);
 
        resJsonData.put(Constants.REQ_KEY_PAGE_VO, new ResPage(pageable.getPageNumber(), pageable.getPageSize(),
                totalPage, totalCount));
 
        resJsonData.put(Constants.RES_KEY_CONTENTS, workflowVos);
 
        return workflowVos;
    }
 
    //  워크플로우를 사용하는 이슈 유형 정보를 추가한다.
    private void setIssueTypeVos(List<WorkflowVo> workflowVos) {
        for (WorkflowVo workflowVo : workflowVos) {
            Workflow workflow = this.getWorkflow(workflowVo.getId());
            List<IssueTypeVo> issueTypeVos = ConvertUtil.convertObjectsToClasses(workflow.getIssueTypes(), IssueTypeVo.class);
            workflowVo.setIssueTypeVos(issueTypeVos);
        }
    }
 
    //  워크플로우를 사용하는 부서 정보를 추가한다.
    private void setDepartmentVos(List<WorkflowVo> workflowVos) {
        for (WorkflowVo workflowVo : workflowVos) {
            Workflow workflow = this.getWorkflow(workflowVo.getId());
 
            List<WorkflowDepartmentVo> workflowDepartmentVos = this.workflowDepartmentService.find(workflow.getId(), null);
            if (workflowDepartmentVos != null && workflowDepartmentVos.size() > 0) {
                IssueStatusVo issueStatusVo = new IssueStatusVo();
                issueStatusVo.setWorkflowDepartmentVos(workflowDepartmentVos);
                workflowVo.addIssueStatusVos(issueStatusVo);
            }
        }
    }
 
    //  워크플로우 상세 정보를 조회한다.
    @Override
    @Transactional(readOnly = true)
    public void detailWorkflow(Map<String, Object> resJsonData, WorkflowCondition workflowCondition) {
        WorkflowVo workflowVo = new WorkflowVo();
 
        if (workflowCondition.getId() != null) {
            Workflow workflow = this.getWorkflow(workflowCondition.getId());
            workflowVo = ConvertUtil.copyProperties(workflow, WorkflowVo.class);
 
            switch (workflowCondition.getDeep()) {
                case "01" : //  연관된 이슈 상태와 전이선 정보를 가져온다.
                    List<IssueStatusVo> issueStatusVos = this.issueStatusService.findByWorkflowId(workflowCondition.getId());
                    for (IssueStatusVo issueStatusVo : issueStatusVos) {
                        List<WorkflowDepartmentVo> workflowDepartmentVos = this.workflowDepartmentService.find(workflowVo.getId(), issueStatusVo.getId());
                        issueStatusVo.setWorkflowDepartmentVos(workflowDepartmentVos);
                    }
                    workflowVo.setIssueStatusVos(issueStatusVos);
                    break;
            }
        }
 
        resJsonData.put(Constants.RES_KEY_CONTENTS, workflowVo);
    }
 
    //  워크플로우를 수정한다.
    @Override
    @Transactional
    public Workflow modifyWorkflow(WorkflowForm workflowForm) {
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
 
        Workflow workflow = this.getWorkflow(workflowForm.getId());
        //  이름 유효성 체크
        this.verifyName(workflowForm.getName(), workflowForm.getId());
        workflow.setName(workflowForm.getName());
 
        // 담당 부서 정보 변경
        this.workflowDepartmentService.modify(workflow, workflowForm.getIssueStatusVos());
        this.workflowTransitionService.modify(workflow, workflowForm.getIssueStatusVos());
        //  워크플로우가 변경되었는지 확인하고 변경되었을 경우 이슈 상태가 없는 이슈는 '생성' 인 이슈 상태로 이동한다.
        this.checkWorkflowChange(workflow);
 
        return workflow;
    }
 
    //  워크플로우가 변경되었는지 확인하고 변경되었을 경우 이슈 상태가 없는 이슈는 '생성' 인 이슈 상태로 이동한다.
    private void checkWorkflowChange(Workflow workflow) {
        for (IssueType issueType : workflow.getIssueTypes()) {
            this.issueService.changeWorkflows(workflow, issueType);
        }
    }
 
    @Override
    @Transactional(readOnly = true)
    public Workflow getWorkflow(Long id) {
        if (id == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_NOT_EXIST));
        }
 
        Workflow workflow = this.findOne(id);
 
        if (workflow == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_NOT_EXIST));
        }
 
        return workflow;
    }
 
    //  워크플로우를 삭제한다.
    @Override
    @Transactional
    public void removeWorkflows(WorkflowForm workflowForm) {
        //  사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다.
        this.workspaceService.checkUseWorkspace();
 
        if (workflowForm.getRemoveIds().size() < 1) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_REMOVE_NOT_SELECT));
        }
 
        for (Long workflowId : workflowForm.getRemoveIds()) {
            this.removeWorkflow(workflowId);
        }
        this.workflowRepository.flush();
    }
 
    private void removeWorkflow(Long workflowId) {
        Workflow workflow = this.getWorkflow(workflowId);
        // 워크플로우 담당부서 삭제
        this.workflowDepartmentService.remove(workflowId);
        //  워크플로우를 이슈 타입에서 사용하고 있는지 확인
        this.checkIssueTypeWorkflow(workflow);
        this.workflowRepository.delete(workflow);
    }
 
    //  워크플로우를 이슈 타입에서 사용하고 있는지 확인
    private void checkIssueTypeWorkflow(Workflow workflow) {
        if (workflow.getIssueTypes().size() > 0) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_USED_ISSUE_TYPE));
        }
    }
 
    //  워크스페이스의 해당 프로젝트 유형에서 사용되는 워크플로우를 찾아온다.
    @Override
    @Transactional(readOnly = true)
    public Workflow findByWorkspaceIdAndProjectType(Long workspaceId, ProjectType projectType) {
        Workflow workflow = this.workflowRepository.findByWorkspaceIdAndProjectType(workspaceId, projectType);
 
        if (workflow == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.WORKFLOW_NOT_EXIST));
        }
 
        return workflow;
    }
 
    //  워크스페이스에 있는 모든 워크플로우 목록을 조회한다.
    @Override
    @Transactional(readOnly = true)
    public List<Workflow> findByWorkspaceId(Long workspaceId) {
        return this.workflowRepository.findByWorkspaceId(workspaceId);
    }
 
    //  워크플로우 목록을 엑셀로 다운로드 한다.
    @Override
    @Transactional
    public ModelAndView downloadExcel(HttpServletRequest request, Model model) {
        //  사용 공간에서 로그인한 사용자가 비활성인지 확인하고 비활성일 경우 엑셀 다운로드를 금지한다.
        ModelAndView modelAndView = this.workspaceService.checkUseExcelDownload(model);
        if (modelAndView != null) {
            return modelAndView;
        }
 
        Map<String, Object> conditions = new HashMap<>();
        //  엑셀 다운로드에 필요한 검색 조건 정보를 추출하고 검색 조건 추출에 오류가 발생하면 경고를 표시해준다.
        modelAndView = this.excelConditionCheck.checkCondition(conditions, request, model);
        if (modelAndView != null) {
            return modelAndView;
        }
 
        WorkflowCondition workflowCondition = WorkflowCondition.make(conditions);
        workflowCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId());
        List<Map<String, Object>> results = this.workflowMapper.find(workflowCondition);
        List<WorkflowVo> workflowVos = ConvertUtil.convertListToListClass(results, WorkflowVo.class);
 
        ExportExcelVo excelInfo = new ExportExcelVo();
        excelInfo.setFileName(this.messageAccessor.message("common.workflowList")); // 워크플로우 목록
        excelInfo.addAttrInfos(new ExportExcelAttrVo("name", this.messageAccessor.message("common.workflow"), 15, ExportExcelAttrVo.ALIGN_LEFT)); // 워크플로우
        //  엑셀에 넣을 데이터
        excelInfo.setDatas(workflowVos);
        model.addAttribute(Constants.EXCEL, excelInfo);
        return new ModelAndView(this.excelView);
    }
}