OWL ITS + 탐지시스템(인터넷 진흥원)
이민희
2022-03-17 916a3cbabe4e50062fce61ff6f2f5d46c05dfbd1
- api로 이슈 추가 시 url/ip로 업체 찾는 코드 수정
1개 파일 추가됨
16개 파일 변경됨
718 ■■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/constant/MsgConstants.java 10 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/constant/Regular.java 12 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/CompanyFieldMapper.java 3 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java 3 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/CompanyFieldServiceImpl.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 444 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/util/CommonUtil.java 38 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/util/ConvertUtil.java 28 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/condition/CompanyFieldCondition.java 30 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/condition/IssueCustomFieldValueCondition.java 9 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/companyField-template.xml 43 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/issue-template.xml 11 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js 20 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/i18n/ko/global.json 1 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/companyField/companyFieldAdd.controller.js 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/companyField/companyFieldList.controller.js 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/companyField/companyFieldModify.controller.js 58 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/constant/MsgConstants.java
@@ -361,4 +361,14 @@
     * api 이슈 생성 완료
     */
    public static final String API_ADD_ISSUE_OK = "API_ADD_ISSUE_OK";
    /**
     * api 파라미터 오류(중복 처리 IP가 두개 이상일 경우)
     */
    public static final String API_PARAMETER_IP_ERROR = "API_PARAMETER_IP_ERROR";
    /**
     * api 파라미터 오류(중복 처리 URL이 두개 이상일 경우)
     */
    public static final String API_PARAMETER_URL_ERROR = "API_PARAMETER_URL_ERROR";
}
src/main/java/kr/wisestone/owl/constant/Regular.java
New file
@@ -0,0 +1,12 @@
package kr.wisestone.owl.constant;
public class Regular {
    /**
     * IP 정규식
     */
    public static final String IP = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
    /**
     * URL 정규식
     */
    public static final String URL = "^((http|https)://)?(www.)?([a-zA-Z0-9]+)\\.[a-z]+([a-zA-z0-9.?#]+)?";
}
src/main/java/kr/wisestone/owl/mapper/CompanyFieldMapper.java
@@ -24,7 +24,4 @@
    List<CompanyField> findByUrlsAndIdNot(CompanyFieldCondition companyFieldCondition);
    List<CompanyField> findByIps(CompanyFieldCondition companyFieldCondition);
    List<CompanyField> findByIpsAndIdNot(CompanyFieldCondition companyFieldCondition);
}
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java
@@ -53,6 +53,7 @@
    List<Map<String, Object>> findNotCompleteByParentIssueId(IssueCondition issueCondition);
    List<Map<String, Object>> findByCustomFieldValueByCompany(IssueCustomFieldValueCondition issueCustomFieldValueCondition);
    List<Map<String, Object>> findByCustomFieldValueBySite(IssueCustomFieldValueCondition issueCustomFieldValueCondition);
}
src/main/java/kr/wisestone/owl/service/impl/CompanyFieldServiceImpl.java
@@ -168,8 +168,6 @@
            List<CompanyField> companyFields = Lists.newArrayList();
            CompanyFieldCondition condition = new CompanyFieldCondition();
            condition.setIpStart(String.valueOf(ipStart));
            condition.setIpEnd(String.valueOf(ipEnd));
            if (id != null) {
                condition.setId(id);
                companyFields = this.companyFieldRepository.findByIdNot(condition.getId());
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -7,7 +7,6 @@
import kr.wisestone.owl.constant.*;
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;
import kr.wisestone.owl.domain.enumType.IssueHistoryType;
import kr.wisestone.owl.domain.enumType.IssueStatusType;
@@ -48,9 +47,9 @@
import java.io.IOException;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Pattern;
import static kr.wisestone.owl.domain.enumType.CustomFieldType.*;
import static kr.wisestone.owl.web.condition.CompanyFieldCondition.IP_DEFAULT;
@Service
public class IssueServiceImpl extends AbstractServiceImpl<Issue, Long, JpaRepository<Issue, Long>> implements IssueService {
@@ -253,7 +252,7 @@
        IssueForm issueForm = ConvertUtil.copyProperties(issueApiForm, IssueForm.class);
//        issueForm.setFiles(issueApiForm.getFiles());
        IssueType issueType = this.issueTypeService.getIssueType(issueApiForm.getIssueTypeId());
        if (issueType == null){
        if (issueType == null) {
            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR));
        }
@@ -267,7 +266,7 @@
                    issueForm.addDepartmentId(departmentId);
                }
            }
        } else if (issueApiForm.getIssueStatusId() == null){
        } else if (issueApiForm.getIssueStatusId() == null) {
            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_ISSUE_STATUS_NOT_EXIST));
        } else if (!this.workflowTransitionService.contains(issueApiForm.getIssueStatusId(), workflow.getId())) {
            //이슈 상태 유효성 확인
@@ -276,7 +275,7 @@
        // 프로젝트 입력
        Project project = issueType.getProject();
        if (project == null){
        if (project == null) {
            throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR));
        }
        issueForm.setProjectId(project.getId());
@@ -311,7 +310,7 @@
                }
                // 중복된 상위 이슈검색
                List<Issue> issues = this.findIssue(issueApiForm, issueForm, customFieldApiOverlaps, user.getId());
                List<Issue> issues = this.findIssue(issueApiForm, issueForm, customFieldApiOverlaps);
                int size = issues.size();
                if (size > 0) {
                    Issue targetIssue = issues.get(0);
@@ -341,11 +340,12 @@
    /**
     * 도메인이 동일한 업체 찾기
     *
     * @param issueForm IssueForm
     * @return IssueForm
     */
    private IssueForm findCompanyField(IssueForm issueForm) {
        if(issueForm.getIssueCustomFields() != null && issueForm.getIssueCustomFields().size() > 0) {
        if (issueForm.getIssueCustomFields() != null && issueForm.getIssueCustomFields().size() > 0) {
            CompanyFieldCondition condition = new CompanyFieldCondition();
            List<Map<String, Object>> companyFields = Lists.newArrayList();
            List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
@@ -355,7 +355,7 @@
            for (Map<String, Object> issueCustomField : issueForm.getIssueCustomFields()) {
                Long customFieldId = MapUtil.getLong(issueCustomField, "customFieldId");
                CustomField customField = this.customFieldService.getCustomField(customFieldId);
                if(customField != null && customField.getCustomFieldType().equals(SITE) && customField.getName().equals("도메인")) {
                if (customField != null && customField.getCustomFieldType().equals(SITE) && customField.getName().equals("도메인")) {
                    String useValue = issueCustomField.get("useValue").toString();
                    String[] urlArr = null;
                    List<String> urls = Lists.newArrayList();
@@ -368,19 +368,19 @@
                    condition.setUrls(urls);
                    companyFields = this.companyFieldService.find(condition);
                    if(companyFields != null && companyFields.size() > 0) {
                    if (companyFields != null && companyFields.size() > 0) {
                        for (Map<String, Object> companyField : companyFields) {
                            CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
                            companyField.put("companyId", companyField.get("id"));
                            issueCompanyFields.add(companyField);
                            if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
                            if (companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
                                Map<String, Object> ispField = this.ispFieldService.find(companyFieldVo.getIspId());
                                if (ispField != null) {
                                    ispField.put("ispId", ispField.get("id"));
                                    issueIspFields.add(ispField);
                                }
                            }
                            if(companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) {
                            if (companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) {
                                Map<String, Object> hostingField = this.hostingFieldService.find(companyFieldVo.getHostingId());
                                if (hostingField != null) {
                                    hostingField.put("hostingId", hostingField.get("id"));
@@ -400,30 +400,84 @@
    }
    /**
     * 입력한 ip가 기존 업체 중에 속해있는지 체크
     *
     * @param ip IP
     * @param startIps 업체 테이블에 존재하는 start_ip(정수로 변환한 값)
     * @param endIps 업체 테이블에 존재하는 end_ip(정수로 변환한 값)
     * @return IP가 속해 있는지 결과 값
     */
    boolean containsIP(Long ip, List<Long> startIps, List<Long> endIps) {
        if (startIps != null && startIps.size() > 0 && endIps != null && endIps.size() > 0) {
            for (int i = 0; i < startIps.size(); i++) {
                if (startIps.get(i) <= ip && endIps.get(i) >= ip) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 조건에 맞는 파트너 정보 찾기
     * @param condition CompanyFieldCondition
     *
     * @param condition          CompanyFieldCondition
     * @param issueCompanyFields List<Map<String, Object>>
     * @param issueIspFields List<Map<String, Object>>
     * @param issueIspFields     List<Map<String, Object>>
     * @param issueHostingFields List<Map<String, Object>>
     */
    private void findPartner(CompanyFieldCondition condition, List<Map<String, Object>> issueCompanyFields
    private CompanyFieldVo findPartner(CompanyFieldCondition condition, List<Map<String, Object>> issueCompanyFields
            , List<Map<String, Object>> issueIspFields, List<Map<String, Object>> issueHostingFields) {
        List<Map<String, Object>> companyFields = this.companyFieldService.find(condition);
        Long ip = condition.getIp();
        List<Map<String, Object>> companyFieldList = Lists.newArrayList();
        if(companyFields != null && companyFields.size() > 0) {
            for (Map<String, Object> companyField : companyFields) {
                CompanyFieldVo companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
        if (ip > IP_DEFAULT) {
            List<CompanyField> companyFields = this.companyFieldService.findAll();
            if (companyFields != null && companyFields.size() > 0) {
                for (CompanyField companyField : companyFields) {
                    if (companyField.getIpStart() != null && companyField.getIpEnd() != null) {
                        List<Long> startIps = ConvertUtil.ipToLongs(companyField.getIpStart());
                        List<Long> endIps = ConvertUtil.ipToLongs(companyField.getIpEnd());
                        if (containsIP(ip, startIps, endIps)) {
                            companyFieldList.add(ConvertUtil.convertObjectToMap(companyField));
                            break;
                        }
                    }
                }
                //  api 사용자정의필드 값에 IP,URL 둘 다 입력 했을 경우
                if (!StringUtils.isEmpty(condition.getUrl()) && companyFieldList.size() > 0) {
                    for (Map<String, Object> companyFieldMap : companyFieldList) {
                        CompanyField companyField = ConvertUtil.convertMapToClass(companyFieldMap, CompanyField.class);
                        if (companyField != null && !StringUtils.isEmpty(companyField.getUrl())) {
                            if (!companyField.getUrl().contains(condition.getUrl())) {
                                companyFieldList.clear();
                            }
                            break;
                        }
                    }
                }
            }
        } else {
            companyFieldList = this.companyFieldService.find(condition);
        }
        CompanyFieldVo companyFieldVo = null;
        if (companyFieldList != null && companyFieldList.size() > 0) {
            for (Map<String, Object> companyField : companyFieldList) {
                companyFieldVo = ConvertUtil.convertMapToClass(companyField, CompanyFieldVo.class);
                companyField.put("companyId", companyField.get("id"));
                issueCompanyFields.add(companyField);
                if(companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
                if (companyFieldVo.getIspId() != null && companyFieldVo.getIspId() != -1) {
                    Map<String, Object> ispField = this.ispFieldService.find(companyFieldVo.getIspId());
                    if (ispField != null) {
                        ispField.put("ispId", ispField.get("id"));
                        issueIspFields.add(ispField);
                    }
                }
                if(companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) {
                if (companyFieldVo.getHostingId() != null && companyFieldVo.getHostingId() != -1) {
                    Map<String, Object> hostingField = this.hostingFieldService.find(companyFieldVo.getHostingId());
                    if (hostingField != null) {
                        hostingField.put("hostingId", hostingField.get("id"));
@@ -432,6 +486,7 @@
                }
            }
        }
        return companyFieldVo;
    }
    private User convertToUser(String token) {
@@ -487,153 +542,101 @@
    }
    /**
     * url 정규식 표현
     * @param url String
     * 사용자정의 필드 검사
     * 도메인 or IP 일 경우만 처리하기 위함
     *
     * @param issueCustomFieldValueForms 사용자 정의 필드 값 배열
     * @return 업체 검색 조건
     */
    private boolean verifyUrl(String url) {
        boolean urlChk = false;
        if (!StringUtils.isEmpty(url)) {
            String reg = "^((http|https)://)?(www.)?([a-zA-Z0-9]+)\\.[a-z]+([a-zA-z0-9.?#]+)?";
            if(Pattern.matches(reg, url)) {
                urlChk = true;
            }
        }
        return urlChk;
    }
    /**
     * ip 정규식 표현
     * @param ip String
     * @return boolean
     */
    private boolean verifyIp(String ip) {
        boolean ipChk = false;
        if (!StringUtils.isEmpty(ip)) {
            if (Pattern.matches("^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\" +
                    ".(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", ip)) {
                ipChk = true;
            }
        }
        return ipChk;
    }
    // 중복된 상위 이슈 검색
    private List<Issue> findIssue(IssueApiForm issueApiform, IssueForm issueForm, List<CustomFieldApiOverlap> customFieldApiOverlaps, Long userId) {
        List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
        List<Issue> resultIssueVos = Lists.newArrayList();
        String comma = ",";
    private CompanyFieldCondition validIssueCustomFieldValue(List<IssueCustomFieldValueForm> issueCustomFieldValueForms, List<CustomFieldApiOverlap> customFieldApiOverlaps) {
        CompanyFieldCondition condition = new CompanyFieldCondition();
        if (issueCustomFieldValueForms.size() > 0) {
            String concatUseValue = "";
            String customFieldType = "";
            int useIdx = 0;
            int cntIp = 0;
            int cntSite = 0;
            IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator();
            Collections.sort(issueCustomFieldValueForms, comp);
            List<String> userValues = Lists.newArrayList();
            CompanyFieldCondition condition = new CompanyFieldCondition();
            List<Map<String, Object>> issueCompanyFields = Lists.newArrayList();
            List<Map<String, Object>> issueIspFields = Lists.newArrayList();
            List<Map<String, Object>> issueHostingFields = Lists.newArrayList();
            for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
                userValues.add(issueCustomFieldValueForm.getUseValue());
                for(CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                for (CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                    if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) {
                        String useValue = issueCustomFieldValueForm.getUseValue();
                        if (useValue.contains(" ")) {
                            useValue = useValue.replace(" ","");
                        }
                        if (this.verifyIp(useValue)) {
                        if (CommonUtil.verifyIp(useValue)) {
                            long ip = ConvertUtil.ipToLong(useValue);
                            customFieldType = IP_ADDRESS.toString();
                            if (cntIp == 0){
                            if (condition.getIp() <= IP_DEFAULT) {
                                condition.setIp(ip);
                            }
                            cntIp ++;
                        }
                        if (this.verifyUrl(useValue)) {
                            customFieldType = SITE.toString();
                            if (cntSite == 0) {
                                condition.setUrl(useValue);
                            }
                            cntSite ++;
                        }
                        /*if (customFieldApiOverlap.getCustomField().getCustomFieldType().equals(IP_ADDRESS)) {
                            long ip = ConvertUtil.ipToLong(useValue);
                            customFieldType = IP_ADDRESS.toString();
                            if (cntIp == 0){
                                condition.setIp(ip);
                            }
                            cntIp ++;
                        }*/
                        /*if(customFieldApiOverlap.getCustomField().getCustomFieldType().equals(SITE)) {
                            customFieldType = SITE.toString();
                            String[] urlArr = null;
                            List<String> urls = Lists.newArrayList();
                            if (useValue.contains(",")) {
                                urlArr = useValue.split(",");
                                urls.addAll(Arrays.asList(urlArr));
                            } else {
                                urls.add(useValue);
                                throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_IP_ERROR));
                            }
                            if (cntSite == 0) {
                                condition.setUrl(urls);
                        } else if (CommonUtil.verifyUrl(useValue)) {
                            if (StringUtils.isEmpty(condition.getUrl())) {
                                condition.setUrl(useValue);
                            } else {
                                throw new ApiParameterException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_URL_ERROR));
                            }
                            cntSite ++;
                        }*/
                        if (useIdx > 0) {
                            concatUseValue = concatUseValue.concat(comma);
                        }
                        concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue());
                        useIdx++;
                    }
                }
            }
        }
        return condition;
    }
            // 추가 할 url or ip에 포함되어있는 파트너 찾기
            if ((condition.getIp() > 0) || (condition.getUrl() != null && !condition.getUrl().equals(""))) {
                this.findPartner(condition, issueCompanyFields, issueIspFields, issueHostingFields);
    String ConvertToString(List<IssueCustomFieldValueForm> issueCustomFieldValueForms, List<CustomFieldApiOverlap> customFieldApiOverlaps) {
        String concatUseValue = "";
        int useIdx = 0;
        for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
            for (CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) {
                    if (useIdx > 0) {
                        concatUseValue = concatUseValue.concat(CommonUtil.COMMA);
                    }
                    concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue());
                    useIdx++;
                }
            }
        }
            issueForm.setIssueCompanyFields(issueCompanyFields);
            issueForm.setIssueIspFields(issueIspFields);
            issueForm.setIssueHostingFields(issueHostingFields);
        return  concatUseValue;
    }
    List<String> GetOverlapUseValues(List<IssueCustomFieldValueForm> issueCustomFieldValueForms) {
        List<String> resultValues = Lists.newArrayList();
        for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
            resultValues.add(issueCustomFieldValueForm.getUseValue());
        }
        return resultValues;
    }
    // 중복된 상위 이슈 검색
    private List<Issue> findIssue(IssueApiForm issueApiform, IssueForm issueForm, List<CustomFieldApiOverlap> customFieldApiOverlaps) {
        List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
        List<Issue> resultIssueVos = Lists.newArrayList();
        CompanyFieldVo companyFieldVo = null;
        CompanyFieldCondition condition = validIssueCustomFieldValue(issueCustomFieldValueForms, customFieldApiOverlaps);
        if (condition.getIp() != null || !StringUtils.isEmpty(condition.getUrl())) {
            // 추가 할 url or ip에 포함되어있는 파트너 찾기
            companyFieldVo = this.findPartner(condition, issueForm.getIssueCompanyFields(), issueForm.getIssueIspFields(), issueForm.getIssueHostingFields());
        }
        if (issueCustomFieldValueForms.size() > 0) {
            String concatUseValue = ConvertToString(issueCustomFieldValueForms, customFieldApiOverlaps);
            List<String> useValues = GetOverlapUseValues(issueCustomFieldValueForms);
            IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
            issueCustomFieldValueCondition.setUseValue(concatUseValue);
            issueCustomFieldValueCondition.setUseValues(userValues);
            issueCustomFieldValueCondition.setUseValues(useValues);
            issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId());
            issueCustomFieldValueCondition.setCustomFieldType(customFieldType);
//            issueCustomFieldValueCondition.setIssueStatusType("CLOSE");
//          issueCustomFieldValueCondition.setIssueStatusType("CLOSE");
            List<Map<String, Object>> results = Lists.newArrayList();
            if (customFieldType.equals(IP_ADDRESS.toString()) && issueForm.getIssueCompanyFields() != null && issueForm.getIssueCompanyFields().size() > 0) {
                long ipValue = 0;
                if (concatUseValue.contains(",")) {
                    String[] arr = concatUseValue.split(",");
                    for (String str : arr) {
                        ipValue = ConvertUtil.ipToLong(str);
                    }
                } else {
                    ipValue = ConvertUtil.ipToLong(concatUseValue);
                }
                issueCustomFieldValueCondition.setUseValue(String.valueOf(ipValue));
            }
            if (issueCustomFieldValueCondition.getCustomFieldType() != null && !issueCustomFieldValueCondition.getCustomFieldType().equals("")) {
                //  사용자정의필드 타입이 IP_ADDRESS 또는 SITE 일 경우
                results = this.issueMapper.findByCustomFieldValueByCompany(issueCustomFieldValueCondition);
            if (companyFieldVo != null) {
                //  url or ip를 통해 업체를 찾았을 경우
                issueCustomFieldValueCondition.setUseValue(companyFieldVo.getUrl());
                results = this.issueMapper.findByCustomFieldValueBySite(issueCustomFieldValueCondition);
            } else {
                results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
            }
@@ -688,7 +691,7 @@
        issue.setIssueType(issueType);
        issue.setPriority(priority);
        issue.setSeverity(severity);
        if (issueForm.getParentIssueId() != null){
        if (issueForm.getParentIssueId() != null) {
            Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
            issue.setParentIssue(parentIssue);
@@ -705,7 +708,7 @@
        issue.setReverseIndex(issue.getId() * -1);  //  쿼리 속도 개선을 위해 리버스 인덱스 생성
        if (issueForm.getParentIssueId() != null){
        if (issueForm.getParentIssueId() != null) {
            Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
            if (issueForm.getIsApi().equals(Issue.IS_API_YES)
                    || (issueForm.getInheritYn() != null && issueForm.getInheritYn())) {
@@ -799,7 +802,7 @@
        issue.setIssueType(issueType);
        issue.setPriority(priority);
        issue.setSeverity(severity);
        if (issueForm.getParentIssueId() != null){
        if (issueForm.getParentIssueId() != null) {
            Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
            issue.setParentIssue(parentIssue);
        }
@@ -851,6 +854,7 @@
    /**
     * Issue를 IssueVo로 변환(하위이슈의 파트너 정보 상속 시 필요)
     *
     * @param issue Issue
     * @return IssueVo
     */
@@ -893,7 +897,7 @@
        issue.setIssueType(issueType);
        issue.setPriority(priority);
        issue.setSeverity(severity);
        if (issueForm.getParentIssueId() != null){
        if (issueForm.getParentIssueId() != null) {
            Issue parentIssue = this.getIssue(issueForm.getParentIssueId());
            issue.setParentIssue(parentIssue);
        }
@@ -1070,7 +1074,8 @@
    /**
     * 날짜 유효성 체크
     * @param startDate 시작 일자(문자)
     *
     * @param startDate    시작 일자(문자)
     * @param completeDate 종료 일자(문자)
     */
    private void checkStartCompleteDate(String startDate, String completeDate) {
@@ -1083,8 +1088,9 @@
    /**
     * 날짜 유효성 체크
     *
     * @param start 시작 일자
     * @param end 종료 일자
     * @param end   종료 일자
     */
    private void checkStartCompleteDate(Date start, Date end) {
        if (start.getTime() > end.getTime()) {
@@ -1100,13 +1106,13 @@
        }
    }
    void SetMyDepartmentId(IssueCondition issueCondition){
    void SetMyDepartmentId(IssueCondition issueCondition) {
        Long loginId = issueCondition.getLoginUserId();
        List<Long> myDepartmentIds = Lists.newArrayList();
        List<UserDepartment> myDepartments = this.userDepartmentRepository.findByUserId(loginId);
        if(myDepartments != null && myDepartments.size() > 0){
            for(UserDepartment myDepartment : myDepartments){
        if (myDepartments != null && myDepartments.size() > 0) {
            for (UserDepartment myDepartment : myDepartments) {
                myDepartmentIds.add(myDepartment.getDepartmentId());
            }
        } else {
@@ -1115,31 +1121,31 @@
        issueCondition.setMyDepartmentIds(myDepartmentIds);
    }
    void SetAllDepartmentId(IssueCondition issueCondition){
    void SetAllDepartmentId(IssueCondition issueCondition) {
        List<Long> departmentIds = Lists.newArrayList();
        List<Map<String, Object>> departmentList = this.departmentMapper.find(null);
        if(departmentList != null && departmentList.size() > 0){
            for(Map<String, Object> department : departmentList){
        if (departmentList != null && departmentList.size() > 0) {
            for (Map<String, Object> department : departmentList) {
                departmentIds.add((Long) department.get("id"));
            }
        }
        issueCondition.setMyDepartmentIds(departmentIds);
    }
    void SetWorkflowDepartment(List<IssueVo> issueVos){
        for(IssueVo issueVo : issueVos){
    void SetWorkflowDepartment(List<IssueVo> issueVos) {
        for (IssueVo issueVo : issueVos) {
            Long issueTypeId = issueVo.getIssueTypeId();
            IssueType issueType = this.issueTypeService.getIssueType(issueTypeId);
            Long workflowId = issueType.getWorkflow().getId();
            List<WorkflowDepartment> workflowDepartmentList = this.workflowDepartmentRepository.findByWorkflowId(workflowId);
            List<Long> workflowDepartmentIds = Lists.newArrayList();
            if(workflowDepartmentList != null && workflowDepartmentList.size()>0){
                for(WorkflowDepartment workflowDepartment : workflowDepartmentList){
            if (workflowDepartmentList != null && workflowDepartmentList.size() > 0) {
                for (WorkflowDepartment workflowDepartment : workflowDepartmentList) {
                    workflowDepartmentIds.add(workflowDepartment.getDepartment().getId());
                }
            }
            if(issueVo.getIssueTypeId().equals(issueTypeId)){
            if (issueVo.getIssueTypeId().equals(issueTypeId)) {
                issueVo.setWorkflowDepartmentIds(workflowDepartmentIds);
            }
        }
@@ -1230,13 +1236,13 @@
    // 하위 이슈 세팅(재귀)
    private void setDownIssues(User user, List<IssueVo> issueVos) {
        for(IssueVo issueVo : issueVos) {
        for (IssueVo issueVo : issueVos) {
            List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueVo.getId());
            List<IssueVo> downIssueVos = Lists.newArrayList();
            IssueCondition issueCondition = new IssueCondition();
            issueCondition.addIssueIds(String.valueOf(issueVo.getId()));
            for(Issue downIssue : downIssues){
            for (Issue downIssue : downIssues) {
                IssueVo addIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class);
                addIssueVo.setIssueTypeId(downIssue.getIssueType().getId());
                downIssueVos.add(addIssueVo);
@@ -1261,9 +1267,9 @@
    // 연관 이슈 세팅
    private void setRelationIssues(List<IssueVo> issueVos) {
        for(IssueVo issueVo : issueVos) {
        for (IssueVo issueVo : issueVos) {
            List<IssueVo> relationIssues = this.issueRelationService.findRelationIssue(issueVo.getId());
            for(IssueVo relationIssue : relationIssues){
            for (IssueVo relationIssue : relationIssues) {
                issueVo.addRelationIssueVo(ConvertUtil.copyProperties(relationIssue, IssueVo.class));
            }
        }
@@ -1271,11 +1277,11 @@
    // 상위 이슈 체크
    private void setParentIssue(List<IssueVo> issueVos) {
        for(IssueVo issueVo : issueVos) {
            if(issueVo.getParentIssueId() != null) {
        for (IssueVo issueVo : issueVos) {
            if (issueVo.getParentIssueId() != null) {
                Issue parentIssue = this.getIssue(issueVo.getParentIssueId());
                //issueVo.setParentIssueVo(ConvertUtil.copyProperties(parentIssue, IssueVo.class));
                if(parentIssue.getIssueCustomFieldValues() == null || parentIssue.getIssueCustomFieldValues().size() == 0){
                if (parentIssue.getIssueCustomFieldValues() == null || parentIssue.getIssueCustomFieldValues().size() == 0) {
                    issueVo.setIssueCustomFieldValueVos(null);
                }
                ConvertUtil.copyProperties(parentIssue, issueVo);
@@ -1286,13 +1292,13 @@
    @Override
    @Transactional(readOnly = true)
    public void setCountDownIssues(List<IssueVo> issueVos) {
        for (IssueVo issueVo : issueVos){
        for (IssueVo issueVo : issueVos) {
            List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueVo.getId()); //하위이슈 가져오기
            if(downIssues != null && downIssues.size() > 0){ //상위이슈 가지고 있는 애들이 있으면
            if (downIssues != null && downIssues.size() > 0) { //상위이슈 가지고 있는 애들이 있으면
                int downIssueAllCount = 0;// 하위이슈 전체 카운트
                int downIssueCount = 0;// 하위이슈 미완료 카운트
                for(Issue downIssue : downIssues){
                    downIssueAllCount ++;
                for (Issue downIssue : downIssues) {
                    downIssueAllCount++;
                    Long parentIssueId = downIssue.getParentIssue().getId();
                    Issue parentIssue = this.getIssue(parentIssueId);
                    IssueVo parentIssueVo = ConvertUtil.copyProperties(parentIssue, IssueVo.class);
@@ -1302,8 +1308,8 @@
                    IssueVo downIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class);
                    downIssueVo.setIssueStatusType(downIssueStatus.getIssueStatusType().toString());
                    if(!downIssueVo.getIssueStatusType().equals("CLOSE")){ //미완료 하위이슈 체크
                        downIssueCount ++;
                    if (!downIssueVo.getIssueStatusType().equals("CLOSE")) { //미완료 하위이슈 체크
                        downIssueCount++;
                    }
                    issueVo.setDownIssueCount(downIssueCount);
@@ -1373,7 +1379,7 @@
                                        IssueCondition issueCondition, Pageable pageable) {
        //  검색 조건을 만든다
        if (!this.makeIssueSearchCondition(issueCondition,Lists.newArrayList("01", "02", "03"), pageable)) {
        if (!this.makeIssueSearchCondition(issueCondition, Lists.newArrayList("01", "02", "03"), pageable)) {
            //  이슈 목록을 찾지 못할 경우 기본 정보로 리턴한다.
            this.notFoundIssueList(resJsonData, pageable);
            return Lists.newArrayList();
@@ -1508,12 +1514,11 @@
        //  프로젝트를 선택하지 않았으면 해당 업무 공간에서 참여하고 있는 프로젝트를 찾는다.
        if (condition.getProjectIds().size() < 1) {
            List<Map<String, Object>> projects = Lists.newArrayList();
            if (this.userWorkspaceService.checkWorkspaceManager(user) || MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT)){
            if (this.userWorkspaceService.checkWorkspaceManager(user) || MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT)) {
                return true;
            }/*else if (MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE)){
                projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectStatues, condition.getProjectType());
            }*/
            else {
            }*/ else {
                projects = this.projectService.findByWorkspaceIdAndIncludeProject(projectStatues, condition.getProjectType());
            }
@@ -1560,7 +1565,7 @@
                    || (MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_PROJECT) &&
                    MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE))) {
                projects = this.projectMapper.findByWorkspaceManagerAll(projectCondition);
            } else  {
            } else {
                projects = this.projectService.findByWorkspaceIdAndIncludeProjectAll(projectCondition);
            }
            List<Long> projectIds = Lists.newArrayList();
@@ -1793,26 +1798,26 @@
        Page<Issue> downIssues = null;
        List<Issue> downIssueList = this.issueRepository.findByParentIssueId(issue.getId());
        if(downIssueList != null && downIssueList.size() > 0) {
        if (downIssueList != null && downIssueList.size() > 0) {
            int startPage = 0;
            if (issueVo.getDownPage() != 0) {
                startPage = (int) Math.floor(issueVo.getDownPage()/issueVo.getDownPageSize());
                startPage = (int) Math.floor(issueVo.getDownPage() / issueVo.getDownPageSize());
            }
            Pageable pageable = PageRequest.of(startPage, issueVo.getDownPageSize());
            if(hideCompleteIssue){
            if (hideCompleteIssue) {
                downIssues = this.issueRepository.findByParentIssueId(issue.getId(), IssueStatusType.CLOSE, pageable);
            }else {
            } else {
                downIssues = this.issueRepository.findByParentIssueId(issue.getId(), pageable);
            }
        }
        if(downIssues != null){
        if (downIssues != null) {
            issueVo.setDownTotalPage(downIssues.getTotalPages());
            issueVo.setDownTotalCount(downIssues.getTotalElements());
            List<IssueVo> resultList = new ArrayList<>();
            for(Issue downIssue : downIssues){
            for (Issue downIssue : downIssues) {
                IssueVo downIssueVo = ConvertUtil.copyProperties(downIssue, IssueVo.class);
                downIssueVo.setIssueTypeVo(ConvertUtil.copyProperties(downIssue.getIssueType(), IssueTypeVo.class));
                downIssueVo.setPriorityVo(ConvertUtil.copyProperties(downIssue.getPriority(), PriorityVo.class));
@@ -1888,12 +1893,12 @@
        this.setIssueCompanyField(issue, issueVo);  //업체 정보 세팅
        this.setIssueIspField(issue, issueVo);  //ISP 정보 세팅
        this.setIssueHostingField(issue, issueVo);  //HOSTING 정보 세팅
        this.setParentIssue(issue,issueVo); //상위 이슈 정보 세팅
        this.setParentIssue(issue, issueVo); //상위 이슈 정보 세팅
    }
    //  상위일감 정보 추가
    private void setParentIssue(Issue issue, IssueVo issueVo) {
        if(issue.getParentIssue() != null){
        if (issue.getParentIssue() != null) {
            issueVo.setParentIssueVo(ConvertUtil.copyProperties(issue.getParentIssue(), IssueVo.class));
        }
    }
@@ -2026,7 +2031,7 @@
            List<UserDepartment> userDepartments = this.userDepartmentRepository.findByDepartmentId(departmentVo.getId());
            if (userDepartments != null && userDepartments.size() > 0) {
                for (UserDepartment userDepartment : userDepartments) {
                    if (userDepartment.getUserId().equals(this.webAppUtil.getLoginId())){
                    if (userDepartment.getUserId().equals(this.webAppUtil.getLoginId())) {
                        issueVo.setModifyPermissionCheck(Boolean.TRUE);
                    }
                }
@@ -2220,7 +2225,7 @@
        checkIssueData.setPriority(priority);
        checkIssueData.setSeverity(severity);
        return  checkIssueData;
        return checkIssueData;
    }
    // 이슈 수정(API용)
@@ -2269,7 +2274,6 @@
    }
    private Issue saveIssue(IssueForm issueForm, CheckIssueData checkIssueData) {
        Issue issue = checkIssueData.getIssue();
        ConvertUtil.copyProperties(issueForm, issue, "id");
@@ -2313,7 +2317,7 @@
        issue = this.saveIssue(issueForm, checkIssueData);
        //this.issueUserService.modifyIssueUser(issue, project.getWorkspace(), issueForm.getUserIds());
        //  담당부서 지정
        if(issueForm.getDepartmentIds().size()>0){
        if (issueForm.getDepartmentIds().size() > 0) {
            this.issueDepartmentService.modifyIssueDepartment(issue, user, project.getWorkspace(), issueForm.getDepartmentIds());
        }
@@ -2584,9 +2588,9 @@
                    //   이슈 담당부서 여부 확인
                    for (DepartmentVo departmentVo : departmentVos) {
                        List<UserDepartment> userDepartments = this.userDepartmentService.findByDepartmentId(departmentVo.getId());
                        if(userDepartments != null && userDepartments.size() > 0) {
                        if (userDepartments != null && userDepartments.size() > 0) {
                            for (UserDepartment userDepartment : userDepartments) {
                                if (userDepartment.getUserId().equals(user.getId())){
                                if (userDepartment.getUserId().equals(user.getId())) {
                                    hasPermission = true;
                                    break;
                                }
@@ -2754,9 +2758,9 @@
        for (Long issueId : issueForm.getRemoveIds()) {
            //하위이슈 체크
            List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueId);
            if(downIssues != null && downIssues.size() > 0){
                for(Issue downIssue : downIssues){
                    if(downIssue.getParentIssue() != null){
            if (downIssues != null && downIssues.size() > 0) {
                for (Issue downIssue : downIssues) {
                    if (downIssue.getParentIssue() != null) {
                        downIssue.setParentIssue(null);
                    }
                }
@@ -2793,8 +2797,8 @@
            removeIds.add(issueId);
            //하위이슈 체크
            List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueId);
            if(downIssues != null && downIssues.size() > 0){
                for(Issue downIssue : downIssues){
            if (downIssues != null && downIssues.size() > 0) {
                for (Issue downIssue : downIssues) {
                    Long downIssueId = downIssue.getId();
                    removeIds.add(downIssueId);
                }
@@ -2827,8 +2831,8 @@
        for (Long issueId : issueForm.getRemoveIds()) {
            //삭제 할 이슈의 하위이슈 체크
            List<Issue> downIssues = this.issueRepository.findByParentIssueId(issueId);
            if(downIssues != null && downIssues.size() > 0){
                for(Issue downIssue : downIssues){
            if (downIssues != null && downIssues.size() > 0) {
                for (Issue downIssue : downIssues) {
                    downIssueId = downIssue.getId();
                }
            }
@@ -2841,7 +2845,7 @@
    private Issue issueRemoves(Long issueId, User user) {
        Issue issue = null;
        if(issueId != null){
        if (issueId != null) {
            issue = this.getIssue(issueId);
        }
        //  이슈 수정 권한을 갖고 있는지 확인
@@ -2861,7 +2865,7 @@
        // 지울 이슈가 연관이슈인지 체크 후 연관이슈 테이블에서도 삭제한다.
        List<IssueRelation> issueRelationList = this.issueRelationRepository.findByRelationIssueId(issueId);
        if (issueRelationList != null && issueRelationList.size() > 0) {
            for(IssueRelation issueRelation : issueRelationList){
            for (IssueRelation issueRelation : issueRelationList) {
                StringBuilder sb = new StringBuilder();
                issueHistoryService.detectRelationIssue(IssueHistoryType.DELETE, issueRelation, sb);
                issueHistoryService.addIssueHistory(issueRelation.getIssue(), IssueHistoryType.MODIFY, sb.toString());
@@ -3068,7 +3072,7 @@
                if (issueVo.getId().equals(MapUtil.getLong(issueCustomFieldValue, "issueId"))) {
                    IssueCustomFieldValueVo issueCustomFieldValueVo = new IssueCustomFieldValueVo();
                    useValues.put("useValue"+count, MapUtil.getString(issueCustomFieldValue, "useValue"));
                    useValues.put("useValue" + count, MapUtil.getString(issueCustomFieldValue, "useValue"));
                    useValues.put("customFieldId", MapUtil.getLong(issueCustomFieldValue, "customFieldId"));
                    issueCustomFieldValueVo.setUseValues(useValues);
@@ -3087,7 +3091,7 @@
    private void setIssueCompanyField(Issue issue, IssueVo issueVo) {
        List<IssueCompanyVo> issueCompanyVos = Lists.newArrayList();
        for(IssueCompany issueCompany : issue.getIssueCompanies()){
        for (IssueCompany issueCompany : issue.getIssueCompanies()) {
            IssueCompanyVo issueCompanyVo = ConvertUtil.copyProperties(issueCompany, IssueCompanyVo.class);
            issueCompanyVo.setId(issueCompany.getId());
            CompanyField companyField = issueCompany.getCompanyField();
@@ -3127,7 +3131,7 @@
    private void setIssueIspField(Issue issue, IssueVo issueVo) {
        List<IssueIspVo> issueIspVos = Lists.newArrayList();
        for(IssueIsp issueIsp : issue.getIssueIspFields()){
        for (IssueIsp issueIsp : issue.getIssueIspFields()) {
            IssueIspVo issueIspVo = ConvertUtil.copyProperties(issueIsp, IssueIspVo.class);
            issueIspVo.setId(issueIsp.getId());
            IspField ispField = issueIsp.getIspField();
@@ -3143,7 +3147,7 @@
    private void setIssueHostingField(Issue issue, IssueVo issueVo) {
        List<IssueHostingVo> issueHostingVos = Lists.newArrayList();
        for(IssueHosting issueHosting : issue.getIssueHostingFields()){
        for (IssueHosting issueHosting : issue.getIssueHostingFields()) {
            IssueHostingVo issueHostingVo = ConvertUtil.copyProperties(issueHosting, IssueHostingVo.class);
            issueHostingVo.setId(issueHosting.getId());
            HostingField hostingField = issueHosting.getHostingField();
@@ -3440,13 +3444,14 @@
    /**
     * 엑셀로 입력한 파트너 정보 저장
     *
     * @param issueForm IssueForm
     */
    private void setIssuePartners(IssueForm issueForm, Issue issue) {
        //issueCompany 등록
        if (issueForm.getIssueCompanyFields() != null && issueForm.getIssueCompanyFields().size() > 0) {
            for (Map<String, Object> issueCompanyMap : issueForm.getIssueCompanyFields()) {
                CompanyField companyField =  ConvertUtil.convertMapToClass(issueCompanyMap, CompanyField.class);
                CompanyField companyField = ConvertUtil.convertMapToClass(issueCompanyMap, CompanyField.class);
                IssueCompany issueCompany = ConvertUtil.convertMapToClass(issueCompanyMap, IssueCompany.class, "id", "registerDate", "modifyDate");
                issueCompany.setCompanyField(companyField);
                issueCompany.setIssue(issue);
@@ -3607,6 +3612,7 @@
    /**
     * 엑셀에 업체명을 입력하지 않았을 경우 같은 도메인 업체 찾기
     *
     * @param issueForm IssueForm
     */
    private void findPartnerByDomain(IssueForm issueForm) {
@@ -3647,7 +3653,7 @@
    //  이슈의 주요 속성을 map 에 저장하여 엑셀 import 에서 지정한 대상(이슈 속성)을 빠르게 찾을 수 있게 한다.
    private void IssueAttributeMapToList(IssueForm issueForm, Map<String, Priority> priorityMaps, Map<String, Severity> severityMaps,
                                         Map<String, DepartmentVo> departmentMaps, Map<String, CustomField> customFieldMaps,Map<String, Long> issueTypeCustomFieldMaps,
                                         Map<String, DepartmentVo> departmentMaps, Map<String, CustomField> customFieldMaps, Map<String, Long> issueTypeCustomFieldMaps,
                                         Map<String, CompanyField> companyFieldMaps, Map<String, IspField> ispFieldMaps, Map<String, HostingField> hostingFieldMaps) {
        Project project = this.projectService.getProject(issueForm.getProjectId());
@@ -3695,11 +3701,12 @@
    /**
     * cell String으로 변환 함수
     * @param cell Cell
     *
     * @param cell   Cell
     * @param isNull boolean
     * @return String
     */
    private String stringToCell (Cell cell, boolean isNull) {
    private String stringToCell(Cell cell, boolean isNull) {
        String cellStr = "";
        if (!isNull) {
            cellStr = CommonUtil.convertExcelStringToCell(cell);
@@ -3714,10 +3721,11 @@
    /**
     * cell NULL 체크 함수
     * 빈 값이 아닌 cell 체크
     *
     * @param cell Cell
     * @return boolean
     */
    private Boolean cellNullCheck (Cell cell) {
    private Boolean cellNullCheck(Cell cell) {
        int cellType = cell.getCellType();
        if (cellType < Cell.CELL_TYPE_BLANK) {
            if (cellType == Cell.CELL_TYPE_STRING) {
@@ -3934,6 +3942,7 @@
            issueForm.setUserIds(userIds);
        }
    }
    //  시작일, 종료일을 IssueForm 에 저장한다.
    private void setIssueFormPeriod(String periodDate, IssueForm issueForm, Boolean checkStartDate, int rowIndex, boolean isNull) throws ParseException {
        if (!isNull) {
@@ -4091,7 +4100,7 @@
        if (issueForm.getSendEmails().size() < 1) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
        }else if (issueForm.getTemplate() != null){
        } else if (issueForm.getTemplate() != null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE));
        }
@@ -4125,7 +4134,7 @@
        if (emailTemplateForm.getSendEmails().size() < 1) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
        }else if (emailTemplateForm.getTemplate() == null){
        } else if (emailTemplateForm.getTemplate() == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE));
        } else if (emailTemplateForm.getIssueId() == null) {
@@ -4145,7 +4154,7 @@
        Locale locale = CommonUtil.getUserLanguage(user.getLanguage());
        String[] sendMails = ConvertUtil.ToArray(emailTemplateForm.getSendEmails());
        for(int i=0; i < sendMails.length; i++) {
        for (int i = 0; i < sendMails.length; i++) {
            sendMails[i] = CommonUtil.decryptAES128(sendMails[i]);
        }
        this.systemEmailService.sendEmail(emailTemplateForm.getTitle(), emailTemplateForm.getTemplate(), sendMails, null, multipartFiles);
@@ -4162,7 +4171,7 @@
        }
        Issue issue = null;
        if(emailCommonForm.getIssueId() != null) {
        if (emailCommonForm.getIssueId() != null) {
            issue = this.getIssue(emailCommonForm.getIssueId());
        }
@@ -4176,7 +4185,7 @@
        Locale locale = CommonUtil.getUserLanguage(user.getLanguage());
        String[] sendMails = ConvertUtil.ToArray(emailCommonForm.getSendEmails());
        for(int i=0; i < sendMails.length; i++) {
        for (int i = 0; i < sendMails.length; i++) {
            sendMails[i] = CommonUtil.decryptAES128(sendMails[i]);
        }
        this.systemEmailService.sendEmail(emailCommonForm.getTitle(), emailCommonForm.getDescription(), sendMails, null, multipartFiles);
@@ -4308,7 +4317,7 @@
        for (Map<String, Object> taskDepartment : taskDepartments) {
            Long taskId = MapUtil.getLong(taskDepartment, "taskId");
            List<DepartmentVo> departmentVos = (List<DepartmentVo>)taskUserSave.get(taskId.toString());
            List<DepartmentVo> departmentVos = (List<DepartmentVo>) taskUserSave.get(taskId.toString());
            departmentVos.add(ConvertUtil.convertMapToClass(taskDepartment, DepartmentVo.class));
        }
@@ -4338,10 +4347,10 @@
            //taskVo.setUserVos(userVos);
            //  담당부서 세팅
            List<DepartmentVo> departmentVos = (List<DepartmentVo>)taskUserSave.get(taskVo.getId().toString());
            List<DepartmentVo> departmentVos = (List<DepartmentVo>) taskUserSave.get(taskVo.getId().toString());
            taskVo.setDepartmentVos(departmentVos);
            List<IssueVo> taskVos = (List<IssueVo>)tasks.get(MapUtil.getString(result, "workflowStatusId"));
            List<IssueVo> taskVos = (List<IssueVo>) tasks.get(MapUtil.getString(result, "workflowStatusId"));
            taskVos.add(taskVo);
            tasks.put(MapUtil.getString(result, "workflowStatusId"), taskVos);
        }
@@ -4363,7 +4372,7 @@
            Issue issue = this.getIssue(downId);
            Issue parentIssue = issue.getParentIssue(); //변경 전 하위이슈의 상위이슈
            if(parentIssue != null && parentIssue.getId().equals(newParentIssueId)){ //변경 전 하위이슈의 상위이슈가 존재 할 경우
            if (parentIssue != null && parentIssue.getId().equals(newParentIssueId)) { //변경 전 하위이슈의 상위이슈가 존재 할 경우
                this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb);
                this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString());
            }
@@ -4372,7 +4381,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);
@@ -4390,7 +4399,8 @@
    /**
     * 상위이슈의 파트너 정보 상속받기
     * @param issue Issue
     *
     * @param issue       Issue
     * @param parentIssue Issue
     * @return Issue
     */
src/main/java/kr/wisestone/owl/util/CommonUtil.java
@@ -3,7 +3,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import kr.wisestone.owl.constant.Regular;
import kr.wisestone.owl.domain.enumType.FileType;
import kr.wisestone.owl.type.LikeType;
import kr.wisestone.owl.vo.DepartmentVo;
@@ -56,7 +56,9 @@
    private static final String PASS_PHRASE = "1024";   //  AES128 암호화에 사용
    private static final int ITERATION_COUNT = 10000;   //  AES128 암호화에 사용
    private static final int KEY_SIZE = 128;    //  AES128 암호화에 사용
    private static final String TMP_UPLOAD_FOLDER = "/tmpUploadFolder/";    //  이슈 생성, 수정에서 파일 업로드할 때 임시 폴더로 사용
    private static final String TMP_UPLOAD_FOLDER = "/tmpUploadFolder/";    //  이슈 생성, 수정에서 파일 업로드할 때 임시 폴더로 사용'
    public static final String COMMA = ","; // 구분자
    public static String getClinetIp() {
        try {
@@ -1042,4 +1044,36 @@
        }
        return "";
    }
    /**
     * 정규식 검사(URL)
     * @param url 대상 문자열(URL)
     * @return  검사 결과
     */
    public static boolean verifyUrl(String url) {
        return verifyRegular(url, Regular.URL);
    }
    /**
     * 정규식 검사(IP)
     * @param ip 대상 문자열(IP)
     * @return 검사 결과
     */
    public static boolean verifyIp(String ip) {
        return  verifyRegular(ip, Regular.IP);
    }
    /**
     * 정규식 검사
     * @param value 대상 문자열
     * @param regular 정규식 검사를 할 정규식 구문
     * @return 검사 결과
     */
    public static boolean verifyRegular(String value, String regular) {
        if (!StringUtils.isEmpty(value)) {
            return Pattern.matches(regular, value);
        }
        return false;
    }
}
src/main/java/kr/wisestone/owl/util/ConvertUtil.java
@@ -3,10 +3,10 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import kr.wisestone.owl.constant.MsgConstants;
import kr.wisestone.owl.constant.Regular;
import kr.wisestone.owl.exception.OwlRuntimeException;
import kr.wisestone.owl.vo.CompanyFieldVo;
import kr.wisestone.owl.vo.IspFieldVo;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -567,9 +567,8 @@
     */
    public static long ipToLong(String ipAddress) {
        long result = 0;
        String reg = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\" +
                        ".(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
        if (!StringUtils.isEmpty(ipAddress) && !Pattern.matches(reg, ipAddress)) {
        if (!StringUtils.isEmpty(ipAddress) && !Pattern.matches(Regular.IP, ipAddress)) {
            return result;
        } else {
            String[] ipAddressArr = ipAddress.split("\\.");
@@ -582,4 +581,23 @@
        return result;
    }
    /**
     * 콤마로 구분된 문자열을 IP 배열로 변환
     * @param ipAddressList 콤마로 구분된 IP 문자열
     * @return 정수로 변환한 배열
     */
    public static List<Long> ipToLongs(String ipAddressList) {
        if (!StringUtils.isEmpty(ipAddressList)) {
            String[] split = ipAddressList.split(CommonUtil.COMMA);
            List<Long> longs = Lists.newArrayList();
            for (String str : split) {
                longs.add(ipToLong(str));
            }
            return longs;
        }
        return null;
    }
}
src/main/java/kr/wisestone/owl/web/condition/CompanyFieldCondition.java
@@ -14,9 +14,7 @@
    private String email;
    private String url;
    private List<String> urls;
    private long ip;
    private String ipStart;
    private String ipEnd;
    private Long ip;
    private List<String> ipStarts = new ArrayList<>();
    private List<String> ipEnds = new ArrayList<>();
    private String memo;
@@ -25,6 +23,12 @@
    private Integer Page;
    private Integer PageSize;
    public static final Long IP_DEFAULT = -1L;
    public CompanyFieldCondition() {
        this.ip = IP_DEFAULT;
    }
    public static CompanyFieldCondition make(Map<String, Object> companyFieldCondition) {
        return ConvertUtil.convertMapToClass(companyFieldCondition, CompanyFieldCondition.class);
@@ -110,28 +114,12 @@
        this.urls = urls;
    }
    public long getIp() {
    public Long getIp() {
        return ip;
    }
    public void setIp(long ip) {
    public void setIp(Long ip) {
        this.ip = ip;
    }
    public String getIpStart() {
        return ipStart;
    }
    public void setIpStart(String ipStart) {
        this.ipStart = ipStart;
    }
    public String getIpEnd() {
        return ipEnd;
    }
    public void setIpEnd(String ipEnd) {
        this.ipEnd = ipEnd;
    }
    public List<String> getIpStarts() {
src/main/java/kr/wisestone/owl/web/condition/IssueCustomFieldValueCondition.java
@@ -35,6 +35,8 @@
     * 이슈 상태 유형(READY / OPEN / CLOSE)
     */
    private String issueStatusType;
    private Long companyFieldId; // IP에 속해있는 업체 찾을 때 사용
    public IssueCustomFieldValueCondition(){}
@@ -172,4 +174,11 @@
        this.useParentIssueId = useParentIssueId;
    }
    public Long getCompanyFieldId() {
        return companyFieldId;
    }
    public void setCompanyFieldId(Long companyFieldId) {
        this.companyFieldId = companyFieldId;
    }
}
src/main/resources/mybatis/query-template/companyField-template.xml
@@ -47,7 +47,7 @@
                </foreach>
            </when>
        </choose>
        <if test="ip != null and ip != ''">
        <if test="ip != null and ip != '' and ip > -1">
            AND INET_ATON(cf.ip_start) <![CDATA[ <= ]]> #{ip} AND INET_ATON(cf.ip_end) >= #{ip}
        </if>
        ORDER BY cf.register_date DESC
@@ -112,47 +112,6 @@
                <foreach collection="urls" item="item" index="index" separator="or" open="(" close=")">
                    cf.url LIKE CONCAT('%',#{item},'%')
                </foreach>
            </when>
        </choose>
        <if test="id != '' and id != null">
            AND cf.id not like CONCAT('%',#{id},'%')
        </if>
    </select>
    <select id="findByIps" resultType="kr.wisestone.owl.domain.CompanyField" parameterType="kr.wisestone.owl.web.condition.CompanyFieldCondition">
        SELECT
        cf.id as id,
        cf.name as name,
        cf.email as email,
        cf.url as url,
        cf.ip_start AS ipStart,
        cf.ip_end AS ipEnd
        FROM
        company_field cf
        WHERE 1=1
        <choose>
            <when test="ipStart != null and ipStart != '' and ipEnd != null and ipEnd != ''">
                AND (INET_ATON(cf.ip_start) BETWEEN #{ipStart} AND #{ipEnd} OR INET_ATON(cf.ip_end) BETWEEN #{ipStart} AND #{ipEnd}
                OR #{ipStart} BETWEEN INET_ATON(cf.ip_start) AND INET_ATON(cf.ip_end) OR #{ipEnd} BETWEEN INET_ATON(cf.ip_start) AND INET_ATON(cf.ip_end))
            </when>
        </choose>
    </select>
    <select id="findByIpsAndIdNot" resultType="kr.wisestone.owl.domain.CompanyField" parameterType="kr.wisestone.owl.web.condition.CompanyFieldCondition">
        SELECT
        cf.id as id,
        cf.name as name,
        cf.email as email,
        cf.url as url,
        cf.ip_start AS ipStart,
        cf.ip_end AS ipEnd
        FROM
        company_field cf
        WHERE 1=1
        <choose>
            <when test="ipStart != null and ipStart != '' and ipEnd != null and ipEnd != ''">
                AND (INET_ATON(cf.ip_start) BETWEEN #{ipStart} AND #{ipEnd} OR INET_ATON(cf.ip_end) BETWEEN #{ipStart} AND #{ipEnd}
                OR #{ipStart} BETWEEN INET_ATON(cf.ip_start) AND INET_ATON(cf.ip_end) OR #{ipEnd} BETWEEN INET_ATON(cf.ip_start) AND INET_ATON(cf.ip_end))
            </when>
        </choose>
        <if test="id != '' and id != null">
src/main/resources/mybatis/query-template/issue-template.xml
@@ -817,11 +817,13 @@
        HAVING concatUseValue LIKE CONCAT('%', #{useValue}, '%')
    </select>
    <!--    IP/SITE 사용자 정의 필드 값이 업체와 동일한 이슈를 조회 -->
    <select id="findByCustomFieldValueByCompany" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition">
    <!-- 사용자 정의 필드 값이(SITE,IP) 업체와 동일한 이슈를 조회 -->
    <select id="findByCustomFieldValueBySite" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition">
        SELECT
        issue.id as id,
        issue.title as title,
        issc.ip_start AS ipStart,
        issc.ip_end AS ipEnd,
        customFieldValue.customFieldType AS customFieldType,
        GROUP_CONCAT(customFieldValue.useValue ORDER BY customFieldValue.customFieldId ASC) AS concatUseValue
        FROM issue issue FORCE INDEX(reverseIndex)
@@ -833,11 +835,8 @@
        ) customFieldValue ON customFieldValue.issueId = issue.id
        LEFT OUTER JOIN issue_company issc ON issc.issue_id = issue.id
        WHERE issue.issue_type_id = #{issueTypeId}
        <if test="customFieldType != null and customFieldType.equals('SITE')">
        <if test="useValue != null and useValue != ''">
            AND issc.url LIKE CONCAT('%',#{useValue},'%')
        </if>
        <if test="customFieldType != null and customFieldType.equals('IP_ADDRESS')">
            AND INET_ATON(issc.ip_start) <![CDATA[ <= ]]> #{useValue} AND INET_ATON(issc.ip_end) >= #{useValue}
        </if>
        <choose>
            <when test="issueStatusType != null">
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
@@ -693,7 +693,25 @@
                                        case "COMPANYFIELD_IP" :
                                            if ($rootScope.isDefined(scope.data.ipStart) && $rootScope.isDefined(scope.data.ipEnd)) {
                                                makeTag += "<span>" + scope.data.ipStart + "<br>~<br>" + scope.data.ipEnd + "</span>";
                                                let ipStartArr = [];
                                                let ipEndArr = [];
                                                if (scope.data.ipStart.indexOf(",") !== -1) {
                                                    scope.data.ipStart = scope.data.ipStart.split(",");
                                                    ipStartArr = angular.copy(scope.data.ipStart);
                                                }
                                                if (scope.data.ipEnd.indexOf(",") !== -1) {
                                                    scope.data.ipEnd = scope.data.ipEnd.split(",");
                                                    ipEndArr = angular.copy(scope.data.ipEnd);
                                                }
                                                if ($rootScope.isDefined(ipStartArr) && ipStartArr.toString() ===  scope.data.ipStart.toString()
                                                        && $rootScope.isDefined(ipEndArr) && ipEndArr.toString() ===  scope.data.ipEnd.toString()) {
                                                    scope.data.ipStart = scope.data.ipStart[0];
                                                    scope.data.ipEnd = scope.data.ipEnd[0];
                                                }
                                                makeTag += "<span>" + scope.data.ipStart + "<br>~</br>" + scope.data.ipEnd + "</span>";
                                            }
                                            break;
src/main/webapp/i18n/ko/global.json
@@ -998,6 +998,7 @@
        "domain" : "도메인",
        "url"   : "url",
        "ipRange" : "ip 대역대",
        "ipRangeFirst" : "ip 대역대(대표)",
        "tel" : "연락처",
        "code" : "코드",
        "email" : "이메일",
src/main/webapp/scripts/app/companyField/companyFieldAdd.controller.js
@@ -382,8 +382,8 @@
                        for (let i=0; i<ipStartArr.length; i++) {
                            if ($rootScope.isDefined(ipStartArr[i+1])) {
                                if((ipStartArr[i] >= ipStartArr[i+1] && ipStartArr[i] <= ipEndArr[i+1])
                                    || (ipEndArr[i] >= ipStartArr[i+1] && ipEndArr[i] <= ipEndArr[i+1])) {
                                if(((ipStartArr[i] >= ipStartArr[i+1] && ipStartArr[i] <= ipEndArr[i+1]) || (ipEndArr[i] >= ipStartArr[i+1] && ipEndArr[i] <= ipEndArr[i+1]))
                                    || (ipStartArr[i+1] >= ipStartArr[i] && ipStartArr[i+1] <= ipEndArr[i]) || (ipEndArr[i+1] >= ipStartArr[i] && ipEndArr[i+1] <= ipEndArr[i])) {
                                    SweetAlert.warning($filter("translate")("companyField.ipRangeError"), $filter("translate")("companyField.ipRangeNotOverlap"));
                                    result = false;
                                    return;
src/main/webapp/scripts/app/companyField/companyFieldList.controller.js
@@ -109,7 +109,7 @@
                        .setDName("url")
                        .setDAlign("text-center"));
                    $scope.vm.tableConfigs.push($tableProvider.config()
                        .setHName("companyField.ipRange")
                        .setHName("companyField.ipRangeFirst")
                        .setHWidth("width-120-p bold")
                        .setDName("ipRange")
                        .setDType("renderer")
src/main/webapp/scripts/app/companyField/companyFieldModify.controller.js
@@ -349,6 +349,13 @@
                        statusName : $scope.vm.form.status
                    };
                    //  ip 대역대 유효성 체크
                    let result = ipRangeChk(content.ipStarts, content.ipEnds);
                    if (!result) {
                        $rootScope.spinner = false;
                        return;
                    }
                    CompanyField.modify($resourceProvider.getContent(
                        content,
                        $resourceProvider.getPageContent(0, 0))).then(function (result) {
@@ -367,6 +374,57 @@
                }
                //  ip 대역대 유효성 검사
                function ipRangeChk(ipStarts, ipEnds) {
                    let result = true;
                    if ($rootScope.isDefined(ipStarts) && $rootScope.isDefined(ipEnds)) {
                        if (ipStarts.length !== ipEnds.length) {
                            SweetAlert.warning($filter("translate")("companyField.ipRangeError"), $filter("translate")("companyField.ipRangeNotEnter"));
                            result = false;
                            return;
                        }
                        let ipStartArr = [];
                        let ipEndArr = [];
                        for (let i=0; i<ipStarts.length; i++) {
                            let ipStart = ipToLong(ipStarts[i]);
                            let ipEnd = ipToLong(ipEnds[i]);
                            if (ipEnd < ipStart) {
                                SweetAlert.warning($filter("translate")("companyField.ipRangeError"), $filter("translate")("companyField.ipStartNotLargerThanEnd"));
                                result = false;
                                return;
                            }
                            ipStartArr.push(ipStart);
                            ipEndArr.push(ipEnd);
                        }
                        for (let i=0; i<ipStartArr.length; i++) {
                            if ($rootScope.isDefined(ipStartArr[i+1])) {
                                if(((ipStartArr[i] >= ipStartArr[i+1] && ipStartArr[i] <= ipEndArr[i+1]) || (ipEndArr[i] >= ipStartArr[i+1] && ipEndArr[i] <= ipEndArr[i+1]))
                                    || (ipStartArr[i+1] >= ipStartArr[i] && ipStartArr[i+1] <= ipEndArr[i]) || (ipEndArr[i+1] >= ipStartArr[i] && ipEndArr[i+1] <= ipEndArr[i])) {
                                    SweetAlert.warning($filter("translate")("companyField.ipRangeError"), $filter("translate")("companyField.ipRangeNotOverlap"));
                                    result = false;
                                    return;
                                }
                            }
                        }
                    }
                    return result;
                }
                //  ip 주소 숫자로 변환
                function ipToLong(ip) {
                    let result = 0;
                    let ipArr = ip.split(".");
                    for (let i=0; i<ipArr.length; i++) {
                        result += parseInt(ipArr[i]) * Math.pow(256, 3-i);
                    }
                    return result;
                }
                // 메일 주소 input 창 추가 버튼
                function addTel() {
                    var arrayFull = true;      // 배열이 가득 차 있는지 여부