OWL ITS + 탐지시스템(인터넷 진흥원)
wyu
2021-12-11 a60879f718fb4fee3bb2b8783a92570f8ead16c3
이메일 템플릿 수정[DB 초기화 필요]
9개 파일 추가됨
16개 파일 변경됨
578 ■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/constant/MsgConstants.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/EmailTemplate.java 41 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/EmailTemplateMapper.java 11 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/repository/EmailTemplateRepository.java 10 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/EmailTemplateService.java 22 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueHistoryService.java 1 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueService.java 3 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/EmailTemplateServiceImpl.java 77 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java 11 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 43 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/EmailTemplateVo.java 36 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/condition/EmailTemplateCondition.java 39 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/controller/EmailTemplateController.java 42 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/controller/IssueController.java 4 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/EmailTemplateForm.java 65 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/migration/V1_13__Alter_Table.sql 11 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/summernote/summernote.js 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/i18n/ko/global.json 1 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issue.js 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueDetail.controller.js 17 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueSendMailPartners.controller.js 95 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/project/projectCustomFieldConfig.controller.js 9 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/main.js 3 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueSendMailPartners.html 30 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/project/projectCustomFieldConfig.html 1 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/constant/MsgConstants.java
@@ -235,6 +235,8 @@
    public static final String ISP_REMOVE_NOT_SELECT = "ISP_REMOVE_NOT_SELECT";   // 삭제할 ISP가 선택되지 않았습니다.
    public static final String PROJECT_NOT_INCLUDE_DEPARTMENT = "PROJECT_NOT_INCLUDE_DEPARTMENT";   // 선택한 부서 중 프로젝트에 참여하고 있지 않은 부서가 있습니다.
    public static final String EMAIL_TEMPLATE_NOT_EXIST = "EMAIL_TEMPLATE_NOT_EXIST"; //  이메일 템플릿을 찾을수 없습니다.
    public static final String API_PARAMETER_ISSUE_TYPE_ERROR = "API_PARAMETER_ISSUE_TYPE_ERROR";     // api 파라미터 오류(이슈타입)
    public static final String API_PARAMETER_PROJECT_ERROR = "API_PARAMETER_PROJECT_ERROR";     // api 파라미터 오류(프로젝트)
    public static final String API_PARAMETER_ERROR = "API_PARAMETER_ERROR";     // api 파라미터 오류
src/main/java/kr/wisestone/owl/domain/EmailTemplate.java
New file
@@ -0,0 +1,41 @@
package kr.wisestone.owl.domain;
import javax.persistence.*;
import java.io.Serializable;
@Entity
public class EmailTemplate extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String template;
    public EmailTemplate() {
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getTemplate() {
        return template;
    }
    public void setTemplate(String template) {
        this.template = template;
    }
}
src/main/java/kr/wisestone/owl/mapper/EmailTemplateMapper.java
New file
@@ -0,0 +1,11 @@
package kr.wisestone.owl.mapper;
import org.springframework.stereotype.Repository;
/**
 * Created by wisestone on 2018-02-26.
 */
@Repository
public interface EmailTemplateMapper {
}
src/main/java/kr/wisestone/owl/repository/EmailTemplateRepository.java
New file
@@ -0,0 +1,10 @@
package kr.wisestone.owl.repository;
import kr.wisestone.owl.domain.CompanyField;
import kr.wisestone.owl.domain.EmailTemplate;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
public interface EmailTemplateRepository extends JpaRepository<EmailTemplate, Long> {
}
src/main/java/kr/wisestone/owl/service/EmailTemplateService.java
New file
@@ -0,0 +1,22 @@
package kr.wisestone.owl.service;
import kr.wisestone.owl.domain.CustomField;
import kr.wisestone.owl.domain.EmailTemplate;
import kr.wisestone.owl.vo.CustomFieldVo;
import kr.wisestone.owl.web.condition.CustomFieldCondition;
import kr.wisestone.owl.web.condition.EmailTemplateCondition;
import kr.wisestone.owl.web.form.CustomFieldForm;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.ui.Model;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
public interface EmailTemplateService extends AbstractService<EmailTemplate, Long, JpaRepository<EmailTemplate, Long>>{
    EmailTemplate getEmailTemplate(Long id);
    void find(Map<String, Object> resJsonData, EmailTemplateCondition make);
}
src/main/java/kr/wisestone/owl/service/IssueHistoryService.java
@@ -61,6 +61,7 @@
    void detectDownIssues(IssueHistoryType type, Issue issue, StringBuilder description);
    void detectSendIssueMail(IssueHistoryType type, IssueForm issueForm, StringBuilder description);
    void detectSendIssueMail(IssueHistoryType type, List<String> sendMails, StringBuilder description);
    void detectIssueCompany(IssueHistoryType type, Map<String, Object> param, IssueCompany issueCompany, StringBuilder description);
src/main/java/kr/wisestone/owl/service/IssueService.java
@@ -8,6 +8,7 @@
import kr.wisestone.owl.web.condition.ApiMonitorCondition;
import kr.wisestone.owl.web.condition.IssueCondition;
import kr.wisestone.owl.web.condition.ProjectCondition;
import kr.wisestone.owl.web.form.EmailTemplateForm;
import kr.wisestone.owl.web.form.IssueApiForm;
import kr.wisestone.owl.web.form.IssueForm;
import org.springframework.data.domain.Pageable;
@@ -87,7 +88,7 @@
    void sendIssueEmail(IssueForm issueForm);
    void sendIssueEmailPartners(IssueForm issueForm);
    void sendIssueEmailPartners(EmailTemplateForm emailTemplateForm);
    void reservationIssue();
src/main/java/kr/wisestone/owl/service/impl/EmailTemplateServiceImpl.java
New file
@@ -0,0 +1,77 @@
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.exception.OwlRuntimeException;
import kr.wisestone.owl.mapper.CompanyFieldMapper;
import kr.wisestone.owl.mapper.EmailTemplateMapper;
import kr.wisestone.owl.repository.CompanyFieldRepository;
import kr.wisestone.owl.repository.EmailTemplateRepository;
import kr.wisestone.owl.repository.HostingFieldRepository;
import kr.wisestone.owl.repository.IspFieldRepository;
import kr.wisestone.owl.service.*;
import kr.wisestone.owl.util.ConvertUtil;
import kr.wisestone.owl.vo.*;
import kr.wisestone.owl.web.condition.CompanyFieldCondition;
import kr.wisestone.owl.web.condition.EmailTemplateCondition;
import kr.wisestone.owl.web.form.CompanyFieldForm;
import kr.wisestone.owl.web.view.ExcelView;
import org.apache.commons.lang3.StringUtils;
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.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class EmailTemplateServiceImpl extends AbstractServiceImpl<EmailTemplate, Long, JpaRepository<EmailTemplate, Long>> implements EmailTemplateService {
    @Autowired
    private EmailTemplateRepository emailTemplateRepository;
    @Autowired
    private EmailTemplateMapper emailTemplateMapper;
    @Autowired
    private EmailTemplateService emailTemplateService;
    @Override
    protected JpaRepository<EmailTemplate, Long> getRepository() {
        return this.emailTemplateRepository;
    }
    @Override
    public void find(Map<String, Object> resJsonData, EmailTemplateCondition condition) {
        EmailTemplate emailTemplate = this.getEmailTemplate(condition.getId());
        EmailTemplateVo emailTemplateVo = ConvertUtil.copyProperties(emailTemplate, EmailTemplateVo.class);
        resJsonData.put(Constants.RES_KEY_CONTENTS, emailTemplateVo);
    }
    @Override
    @Transactional(readOnly = true)
    public EmailTemplate getEmailTemplate(Long id) {
        if (id == null) {
            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EMAIL_TEMPLATE_NOT_EXIST));
        }
        EmailTemplate emailTemplate = this.findOne(id);
        if (emailTemplate == null) {
            throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.EMAIL_TEMPLATE_NOT_EXIST));
        }
        return emailTemplate;
    }
}
src/main/java/kr/wisestone/owl/service/impl/IssueHistoryServiceImpl.java
@@ -16,6 +16,7 @@
import kr.wisestone.owl.vo.IssueHistoryVo;
import kr.wisestone.owl.vo.IssueVo;
import kr.wisestone.owl.web.condition.IssueHistoryCondition;
import kr.wisestone.owl.web.form.EmailTemplateForm;
import kr.wisestone.owl.web.form.IssueForm;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -529,10 +530,16 @@
    // 이슈 메일 전송 정보를 기록한다.
    @Override
    public void detectSendIssueMail(IssueHistoryType type, IssueForm issueForm, StringBuilder description) {
        this.detectSendIssueMail(type, issueForm.getSendEmails(), description);
    }
    // 이슈 메일 전송 정보를 기록한다.
    @Override
    public void detectSendIssueMail(IssueHistoryType type, List<String> sendMails, StringBuilder description) {
        if (type == IssueHistoryType.SEND) {
            description.append("<span translate=\"issue.sendIssueMailHistory\">이슈 메일 전송을 완료했습니다. </span>");
            if(issueForm.getSendEmails() != null && issueForm.getSendEmails().size() > 0){
                for (String sendEmail : issueForm.getSendEmails()){
            if(sendMails != null && sendMails.size() > 0){
                for (String sendEmail : sendMails){
                    description.append("<span class=\"text-primary bold\">&nbsp;>&nbsp;" + CommonUtil.decryptAES128(sendEmail) + "</span>");
                }
            }
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -788,10 +788,10 @@
        //  Map 에 있는 데이터를 IssueVo 데이터로 변환한다.
        this.setMapToIssueVo(results, issueVos, issueCondition, user);
        if (issueCondition.getTree()) {
//        if (issueCondition.getTree()) {
            this.setDownIssues(issueVos);
            this.setRelationIssues(issueVos);
        }
//        }
        this.setCountDownIssues(results, issueVos);
        this.SetWorkflowDepartment(issueVos); //워크플로우에 설정한 담당부서 가져오기
@@ -3262,45 +3262,36 @@
    //  이슈를 템플릿에 따라 파트너 담당자에게 메일로 발송한다.
    @Override
    @Transactional(readOnly = true)
    public void sendIssueEmailPartners(IssueForm issueForm) {
        if (issueForm.getSendEmails().size() < 1) {
    public void sendIssueEmailPartners(EmailTemplateForm emailTemplateForm) {
        if (emailTemplateForm.getSendEmails().size() < 1) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER));
        }else if (issueForm.getTemplate() == null){
        }else if (emailTemplateForm.getTemplate() == null){
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SELECT_TEMPLATE));
        } else if (emailTemplateForm.getIssueId() == null) {
            throw new OwlRuntimeException(
                    this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST));
        }
        Issue issue = this.getIssue(issueForm.getId());
        Issue issue = this.getIssue(emailTemplateForm.getIssueId());
        Map<String, Object> issueMap = new HashMap<>();
        //  이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다.
        this.makeIssueMapToIssue(issue, issueMap);
        //  발신자 표시
        User user = this.webAppUtil.getLoginUserObject();
        UserVo toUser = this.webAppUtil.getLoginUser();
        issueMap.put("toUser", toUser.getName() + "(" + CommonUtil.decryptAES128(toUser.getAccount()) + ")");
        // 이슈 링크
        String projectKey = issue.getProject().getProjectKey();
        Long IssueNumber = issue.getIssueNumber();
        String link = this.configuration.getEmailSendUrl() + "/#/issues/issueList?projectKey=" + projectKey + "&issueNumber=" + IssueNumber.toString();
        issueMap.put("issueLink", link);
        issueMap.put("projectLink", link);
        //  사용자 시스템 기능 사용 정보 수집
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL));
        StringBuilder sb = new StringBuilder();
        if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_1.toString())){
            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_1, issueMap, null);
        }else if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_2.toString())){
            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_2, issueMap, null);
        }else if(issueForm.getTemplate().equals(EmailType.ISSUE_SEND_3.toString())){
            this.systemEmailService.directEmail(ConvertUtil.ToArray(issueForm.getSendEmails()), EmailType.ISSUE_SEND_3, issueMap, null);
        Locale locale = CommonUtil.getUserLanguage(user.getLanguage());
        String[] sendMails = ConvertUtil.ToArray(emailTemplateForm.getSendEmails());
        for(int i=0; i < sendMails.length; i++) {
            sendMails[i] = CommonUtil.decryptAES128(sendMails[i]);
        }
        //메일 전송 이력 남기기
        this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, issueForm, sb);
        this.systemEmailService.sendEmail(emailTemplateForm.getTitle(), emailTemplateForm.getTemplate(), sendMails, null);
        this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, emailTemplateForm.getSendEmails(), sb);
        this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString());
    }
src/main/java/kr/wisestone/owl/vo/EmailTemplateVo.java
New file
@@ -0,0 +1,36 @@
package kr.wisestone.owl.vo;
public class EmailTemplateVo extends UsePartnerVo {
    private Long id;
    private String title;
    private String template;
    public EmailTemplateVo() {}
    @Override
    public Long getId() {
        return id;
    }
    @Override
    public void setId(Long id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getTemplate() {
        return template;
    }
    public void setTemplate(String template) {
        this.template = template;
    }
}
src/main/java/kr/wisestone/owl/web/condition/EmailTemplateCondition.java
New file
@@ -0,0 +1,39 @@
package kr.wisestone.owl.web.condition;
import kr.wisestone.owl.util.ConvertUtil;
import java.util.Map;
public class EmailTemplateCondition {
    private Long id;
    private String title;
    private String template;
    public static EmailTemplateCondition make(Map<String, Object> condition) {
        return ConvertUtil.convertMapToClass(condition, EmailTemplateCondition.class);
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getTemplate() {
        return template;
    }
    public void setTemplate(String template) {
        this.template = template;
    }
}
src/main/java/kr/wisestone/owl/web/controller/EmailTemplateController.java
New file
@@ -0,0 +1,42 @@
package kr.wisestone.owl.web.controller;
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.service.CompanyFieldService;
import kr.wisestone.owl.service.EmailTemplateService;
import kr.wisestone.owl.web.condition.CompanyFieldCondition;
import kr.wisestone.owl.web.condition.EmailTemplateCondition;
import kr.wisestone.owl.web.form.CompanyFieldForm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Controller
public class EmailTemplateController extends BaseController{
    @Autowired
    private EmailTemplateService emailTemplateService;
    // 템플릿 가져오기
    @RequestMapping(value = "/emailTemplate/find", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public
    @ResponseBody
    Map<String, Object> find(@RequestBody Map<String, Map<String, Object>> params) {
        Map<String, Object> resJsonData = new HashMap<>();
        this.emailTemplateService.find(resJsonData, EmailTemplateCondition.make(params.get(Constants.REQ_KEY_CONTENT)));
        return this.setSuccessMessage(resJsonData);
    }
}
src/main/java/kr/wisestone/owl/web/controller/IssueController.java
@@ -6,6 +6,7 @@
import kr.wisestone.owl.util.ConvertUtil;
import kr.wisestone.owl.web.condition.ApiMonitorCondition;
import kr.wisestone.owl.web.condition.IssueCondition;
import kr.wisestone.owl.web.form.EmailTemplateForm;
import kr.wisestone.owl.web.form.IssueForm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -209,7 +210,8 @@
    @ResponseBody
    Map<String, Object> sendEmailPartners(@RequestBody Map<String, Map<String, Object>> params) {
        Map<String, Object> resJsonData = new HashMap<>();
        this.issueService.sendIssueEmailPartners(IssueForm.make(params.get(Constants.REQ_KEY_CONTENT)));
        this.issueService.sendIssueEmailPartners(EmailTemplateForm.make(params.get(Constants.REQ_KEY_CONTENT)));
//        this.issueService.sendIssueEmailPartners(IssueForm.make(params.get(Constants.REQ_KEY_CONTENT)));
        return this.setSuccessMessage(resJsonData);
    }
src/main/java/kr/wisestone/owl/web/form/EmailTemplateForm.java
New file
@@ -0,0 +1,65 @@
package kr.wisestone.owl.web.form;
import com.google.common.collect.Lists;
import kr.wisestone.owl.util.ConvertUtil;
import kr.wisestone.owl.util.MapUtil;
import java.util.List;
import java.util.Map;
public class EmailTemplateForm {
    private Long id;
    private String title;
    private String template;
    private Long issueId;
    private List<String> sendEmails = Lists.newArrayList();
    public static EmailTemplateForm make(Map<String, Object> params) {
        EmailTemplateForm form = ConvertUtil.convertMapToClass(params, EmailTemplateForm.class);
        //  메일 발송자 정보
        if (MapUtil.getStrings(params, "sendEmails") != null) {
            form.setSendEmails(MapUtil.getStrings(params, "sendEmails"));
        }
        return  form;
    }
    public List<String> getSendEmails() {
        return sendEmails;
    }
    public void setSendEmails(List<String> sendEmails) {
        this.sendEmails = sendEmails;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getTemplate() {
        return template;
    }
    public void setTemplate(String template) {
        this.template = template;
    }
    public Long getIssueId() {
        return issueId;
    }
    public void setIssueId(Long issueId) {
        this.issueId = issueId;
    }
}
src/main/resources/migration/V1_13__Alter_Table.sql
@@ -22,6 +22,17 @@
ALTER TABLE `company_field` ADD INDEX `ispIdIndex`(`isp_id`);
ALTER TABLE `company_field` ADD INDEX `hostingIdIndex`(`hosting_id`);
CREATE TABLE `email_template`(
    `id` BIGINT(11) AUTO_INCREMENT,
    `title` VARCHAR (255) NOT NULL,
    `template` mediumtext NOT NULL,
    `register_id` BIGINT(20) NOT NULL,
    `register_date` TIMESTAMP NULL,
    `modify_id` BIGINT(20) NOT NULL,
    `modify_date` TIMESTAMP NULL,
    PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
src/main/webapp/custom_components/summernote/summernote.js
@@ -7034,7 +7034,6 @@
        };
    };
    $.summernote = $.extend($.summernote, {
        version: '0.8.2',
        ui: ui,
@@ -7092,6 +7091,7 @@
                ['insert', ['link', 'picture', 'video']]
            ],
            // popover
            popover: {
                image: [
src/main/webapp/i18n/ko/global.json
@@ -707,6 +707,7 @@
        "selectDestinationDeletion": "삭제 대상을 선택하세요.",
        "deleteFailed": "삭제 실패",
        "deleteSucceeded": "삭제 성공",
        "emailTemplate": "이메일 템플릿",
        "content": "내용",
        "selectTarget": "대상 선택",
        "period": "기간",
src/main/webapp/scripts/app/issue/issue.js
@@ -35,7 +35,7 @@
                            require([
                                'issueListTimelineController', 'issueManagerController', 'issueListController', 'issueAddController', 'issueModifyController', 'issueDetailController', 'issueAddRelationController', 'issueImportExcelController',
                                'chartLoader', 'jsTable', 'jsTree', 'tableColumnGenerator', 'treeColumnGenerator', 'modalFormAutoScroll', 'summerNote', 'summerNote-ko-KR', 'fullScroll', 'workflowService', 'priorityService', 'issueSearchService', 'issueTableConfigService', 'inputRegex',
                                'severityService', 'issueTypeService', 'issueTypeCustomFieldService', 'issueService', 'issueStatusService', 'issueUserService','issueDepartmentService','issueModifyUserController', 'issueModifyDepartmentController', 'customFieldService', 'issueSearchFieldKeyViewElement',
                                'severityService', 'issueTypeService', 'issueTypeCustomFieldService', 'issueService', 'issueStatusService', 'emailTemplateService','issueUserService','issueDepartmentService','issueModifyUserController', 'issueModifyDepartmentController', 'customFieldService', 'issueSearchFieldKeyViewElement',
                                'issueSearchCustomFieldViewElement', 'tableUserImage', 'fullScroll', 'issueCommentService', 'detectIssueEditor', 'formSubmit', 'issueModifyStatusController', 'downIssueModifyStatusController', 'jsShortCut',
                                'issueAddTableConfigController','issueAddRelationTableConfigController','issueAddDownTableConfigController','domAppend', 'issueDetailImagePreview', 'issueSendMailPartnersController', 'htmlDiff', 'issueVersionViewController', 'issueVersionService',
                                'jsHtmlDiff', 'issueReservationController', 'issueReservationService', 'issueVersionService', 'issueStatusAutoFocus', 'issueRelationService'
src/main/webapp/scripts/app/issue/issueDetail.controller.js
@@ -642,15 +642,20 @@
                        }
                    });
                }
                // todo 모르겠다.....
                 // 이슈명을 클릭하면 이슈 상세 정보를 조회한다.
                 // $rootScope.$on("getIssueDetail", function (event, args) {
                 //     $scope.vm.viewer.id = args["id"];
                 //     $scope.fn.getIssueDetail();
                 // });
                //  이슈명을 클릭하면 이슈 상세 정보를 조회한다.
                // $scope.$on("getIssueDetail", function (event, args) {
                //     $scope.vm.viewer.id = args["id"];
                //     $scope.fn.getIssueDetail();
                // });
                
                // 이메일 보낸후 상세화면 갱신
                // todo 이거 뭐지...
                //  $rootScope.$on("getIssueDetail", function (event, args) {
                //      $scope.fn.getIssueDetail();
                //  });
@@ -658,12 +663,6 @@
                $scope.$on("getIssueDetail", function (event, args) {
                    $scope.fn.getIssueDetail();
                });
                //  이슈명을 클릭하면 이슈 상세 정보를 조회한다.
                // $scope.$on("getIssueDetail", function (event, args) {
                //     $scope.vm.viewer.id = args["id"];
                //     $scope.fn.getIssueDetail();
                // });
                $scope.$watch(function() {
                    return $rootScope.currentDetailIssueId;
@@ -673,8 +672,6 @@
                        $scope.fn.getIssueDetail();
                    }
                }, true);
                //  초기화 해야할 할목을 지정하여 다른 이슈를 클릭할 때 초기화해준다.
                function initReload() {
src/main/webapp/scripts/app/issue/issueSendMailPartners.controller.js
@@ -5,8 +5,8 @@
        'angular'
    ],
    function (app, angular) {
        app.controller('issueSendMailPartnersController', ['$scope', '$rootScope', '$q','$log', '$resourceProvider', '$uibModalInstance', '$controller', '$injector', 'SweetAlert', '$filter', 'parameter', 'Issue',
            function ($scope, $rootScope, $q, $log, $resourceProvider, $uibModalInstance, $controller, $injector, SweetAlert, $filter, parameter, Issue) {
        app.controller('issueSendMailPartnersController', ['$scope', '$rootScope', '$q','$log', '$resourceProvider', '$uibModalInstance', '$controller', '$injector', 'SweetAlert', '$filter', 'parameter', 'Issue', 'EmailTemplate',
            function ($scope, $rootScope, $q, $log, $resourceProvider, $uibModalInstance, $controller, $injector, SweetAlert, $filter, parameter, Issue, EmailTemplate) {
                $scope.fn = {
                    getUserListCallBack : getUserListCallBack,  //  사용자 auto complete callback function
@@ -15,7 +15,8 @@
                    removeMailTarget : removeMailTarget,
                    formSubmit : formSubmit,    //  폼 전송
                    formCheck : formCheck,   //  폼 체크
                    changeTemplate : changeTemplate,
                    onChangeEmailTemplate : onChangeEmailTemplate, // 이메일 템플릿 선택시 실행
                    getEmailTemplateList : getEmailTemplateList // 이메일 템플릿 목록 가져오기
                    // showEmailTemplate : showEmailTemplate,
                };
@@ -27,7 +28,6 @@
                    html : "issueSendMailPartners.html",
                    form : {
                        id : parameter.issueId,  //  이슈 번호
                        template : "ISSUE_SEND_2",
                        projects : [{ id : parameter.projectId}],  //  프로젝트
                        mailUsers : parameter.partners.slice()   //  메일 전송받는 사용자
                    },
@@ -37,10 +37,58 @@
                            page : 0,
                            totalPage : 0
                        }
                    }
                    },
                    emailTitle : "",
                    emailTemplateId : -1,
                    emailTemplates : []
                };
                angular.extend(this, $controller('autoCompleteController', {$scope : $scope, $injector : $injector}));
                function onChangeEmailTemplate() {
                    var content = {
                        id : $scope.vm.emailTemplateId
                    }
                    EmailTemplate.find($resourceProvider.getContent(
                        content,
                        $resourceProvider.getPageContent(0, 10))).then(function (result) {
                        if (result.data.message.status === "success") {
                            $scope.vm.html = result.data.data.template;
                        }
                        else {
                            SweetAlert.error($filter("translate")("issue.failedIssueMail"), result.data.message.message); // "이슈 메일 발송 실패"
                        }
                        $rootScope.spinner = false;
                    });
                }
                function getEmailTemplateList() {
                    $scope.vm.emailTemplates.push({
                            id : 1,
                            title : "템플릿1"
                    });
                    $scope.vm.emailTemplates.push({
                            id : 2,
                            title : "템플릿2"
                    });
                    $scope.vm.emailTemplates.push({
                            id : 3,
                            title : "템플릿3"
                    });
                    $scope.vm.emailTemplateId = 1;
                    $scope.vm.emailTitle = "";
                    $scope.vm.emailTemplates.forEach(function (emailTemplate) {
                        if (emailTemplate.id === $scope.vm.emailTemplateId) {
                            $scope.vm.emailTitle = emailTemplate.title;
                        }
                    })
                }
                //  사용자 삭제
                function removeMailTarget(index) {
@@ -63,8 +111,10 @@
                function formSubmit() {
                    $rootScope.spinner = true;
                    var content = {
                        id : $scope.vm.form.id,
                        template : $scope.vm.form.template,
                        id : $scope.vm.emailTemplateId,
                        template : $scope.vm.html,
                        title : $scope.vm.emailTitle,
                        issueId : $scope.vm.form.id,
                        sendEmails : (function () {
                            var sendEmails = [];
@@ -125,36 +175,7 @@
                    return deferred.promise;
                }
                function changeTemplate(templateId){
                    $scope.vm.form.template = templateId;
                    var elements = document.getElementsByClassName("TemplateIMG");
                    for (let i = elements.length - 1; i >= 0; i--) {
                        if (elements[i].id === templateId) {
                            elements[i].className += " TemplateIMG-selected";
                        } else {
                            elements[i].className = "TemplateIMG";
                        }
                    }
                    // for(let i = 0 ; i <= 3 ; i++){
                    //     $('#ISSUE_SEND_'+i).click(function(){
                    //         $('#Email-Template'+i,'#Email-Template4').slideToggle('slow');
                    //     });
                    // }
                    // $("#ISSUE_SEND_1").click(function () {
                    //     $("#Email-Template1,#Email-Template4").slideToggle(0);
                    // });
                    //
                    // $("#ISSUE_SEND_2").click(function() {
                    //     $( "#Email-Template2,#Email-Template4" ).slideToggle(0);
                    // });
                    //
                    // $("#ISSUE_SEND_3").click(function() {
                    //     $( "#Email-Template3,#Email-Template4" ).slideToggle(0);
                    // });
                }
                $scope.fn.getEmailTemplateList();
            }]);
    });
src/main/webapp/scripts/app/project/projectCustomFieldConfig.controller.js
@@ -19,7 +19,7 @@
                    getCustomFields : getCustomFields,
                    startExecute : startExecute,
                    issueTypeChange : issueTypeChange,
                    activeSortable : activeSortable(),
                    activeSortable : activeSortable,
                };
                $scope.vm = {
@@ -41,8 +41,14 @@
                    IssueType.find($resourceProvider.getContent({},
                        $resourceProvider.getPageContent(0, 1000))).then(function (result) {
                        // completeIssueStatusVo
                        if (result.data.message.status === "success") {
                            $scope.vm.issueTypes = result.data.data;
                            for (let i = 0; i < $scope.vm.issueTypes.length; i++) {
                                if ($scope.vm.issueTypes[i].completeIssueStatusVo !== null) {
                                    $scope.vm.issueTypes.push()
                                }
                            }
                        }
                        else {
                            SweetAlert.swal($filter("translate")("issue.failedToIssueTypeListLookup"), result.data.message.message, "error"); // "이슈 유형 목록 조회 실패"
@@ -63,7 +69,6 @@
                        if (result.data.message.status === "success") {
                            $scope.vm.customFields = result.data.data;
                            $scope.vm.originCustomFields = angular.copy(result.data.data);  //  사용자 정의 필드 복구에 사용
                        }
                        else {
src/main/webapp/scripts/main.js
@@ -360,6 +360,9 @@
        'hostingFieldListController' : 'app/hostingField/hostingFieldList.controller', // 호스팅 목록 컨트롤러
        'hostingFieldAddController' : 'app/hostingField/hostingFieldAdd.controller', // 호스팅 생성 컨트롤러
        'hostingFieldModifyController' : 'app/hostingField/hostingFieldModify.controller', // 호스팅 수정 컨트롤러
        /* 이메일 템플릿*/
        'emailTemplateService' : 'components/emailTemplate/emailTemplate.service',  // 호스팅 관련된 통신 담당
    },
    shim : {
        'jquery-ui' : {
src/main/webapp/views/issue/issueSendMailPartners.html
@@ -33,21 +33,21 @@
                                       extra-settings="{ displayProp : 'name' , idProp : 'id', imageable : false, imagePathProp : 'profile',
                                       type : 'partner', maxlength : 100, autoResize : true, stopRemoveBodyEvent : true }"></js-input-autocomplete>
                    <div class="Template-area mt-20">
                        <label class="issue-detail-label">이메일 템플릿</label>
                            <div class="mt-10" ng-init="fn.changeTemplate('ISSUE_SEND_1')">
                                <img id="ISSUE_SEND_1" class="TemplateIMG" src="assets/images/emailthumb-badcode.png" ng-click="fn.changeTemplate('ISSUE_SEND_1')">
                                <img id="ISSUE_SEND_2" class="TemplateIMG" src="assets/images/emailthumb-domain.png" ng-click="fn.changeTemplate('ISSUE_SEND_2')">
                                <img id="ISSUE_SEND_3" class="TemplateIMG" src="assets/images/emailthumb-hosting.png" ng-click="fn.changeTemplate('ISSUE_SEND_3')">
                                <div>
                                    <span class="email_font">악성코드</span>
                                    <span class="email_font offset-detail-3">도메인</span>
                                    <span class="email_font offset-detail-3">호스팅</span>
                                </div>
                            </div>
                        <div>
                            <img ng-show="vm.form.template == 'ISSUE_SEND_1'" style="margin: 50px auto 0;" id="Email-Template1" src="assets/images/emailthumb-badcode.png">
                            <img ng-show="vm.form.template == 'ISSUE_SEND_2'" style="margin: 50px auto 0;" id="Email-Template2" src="assets/images/emailthumb-domain.png">
                            <img ng-show="vm.form.template == 'ISSUE_SEND_3'" style="margin: 50px auto 0;" id="Email-Template3" src="assets/images/emailthumb-hosting.png">
                        <div class="form-group mb10">
                            <label for="emailTemplateForm" class="issue-label">
                                <span translate="common.emailTemplate">이메일 템플릿</span>
                            </label>
                            <select id="emailTemplateForm"
                                    name="emailTemplate"
                                    class="form-control input-sm issue-select-label"
                                    ng-model="vm.emailTemplateId"
                                    ng-change="fn.onChangeEmailTemplate()"
                                    required>
                                <option ng-repeat="emailTemplate in vm.emailTemplates"
                                        value="{{emailTemplate.id}}"
                                        translate="{{emailTemplate.title}}">
                                </option>
                            </select>
                        </div>
                    </div>
                <summernote
src/main/webapp/views/project/projectCustomFieldConfig.html
@@ -18,6 +18,7 @@
                        required
                        ng-model="vm.form.issueTypeId"
                        ng-change="fn.issueTypeChange()">
<!--                    ng-if="relationCustomField.checked == 'false'"-->
                    <option value="" translate="common.choose">선택하세요.</option>
                    <option ng-value="issueType.id" ng-repeat="issueType in vm.issueTypes">{{::issueType.name}}</option>
                </select>