| | |
| | | import org.springframework.security.core.session.SessionRegistry; |
| | | import org.springframework.security.crypto.factory.PasswordEncoderFactories; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
| | | import org.springframework.security.web.session.ConcurrentSessionFilter; |
| | | import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices; |
| | | |
| | |
| | | .antMatchers("/guide/detail").permitAll() |
| | | .antMatchers("/language/change").permitAll() |
| | | .antMatchers("/security/*").permitAll() |
| | | .antMatchers("/api/issue").permitAll() |
| | | .antMatchers("/**/*").authenticated(); |
| | | // http.addFilter(new CustomAuthenticationFilter()); |
| | | // http.addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); |
| | | |
| | | |
| | | http.rememberMe() |
| | |
| | | public static final String USER_NOT_EQUAL_PASSWORD = "USER_NOT_EQUAL_PASSWORD"; // 비밀번호가 맞지 않습니다. |
| | | public static final String USER_NOT_EXIST = "USER_NOT_EXIST"; // 사용자가 존재하지 않습니다. |
| | | public static final String USER_NOT_AUTHORIZED = "USER_NOT_AUTHORIZED"; // 사용자 인증 권한이 없습니다. |
| | | public static final String ERROR_TOKEN = "USER_NOT_AUTHORIZED_TOKEN"; // 유효하지 않은 토큰입니다. |
| | | public static final String USER_EXPIRED_PASSWORD = "USER_EXPIRED_PASSWORD"; // 비밀번호가 만료되었습니다. |
| | | public static final String USER_RETURN_PASSWORD_NOT_PROVIDER_SOCIAL_JOIN_USER = "USER_RETURN_PASSWORD_NOT_PROVIDER_SOCIAL_JOIN_USER"; // 비밀번호 찾기 기능을 소셜 계정 가입 사용자는 사용할 수 없습니다. |
| | | public static final String USER_NOT_USE_ACTIVE_STATUS = "USER_NOT_USE_ACTIVE_STATUS"; // 사용자는 활성 상태가 아니면 로그인할 수 없습니다. |
| | |
| | | public static final String ISP_NOT_EXIST = "ISP_NOT_EXIST"; // ISP가 존재하지 않습니다. |
| | | 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 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_USER_ERROR = "API_USER_ERROR"; // api 사용자 오류 |
| | | } |
| | |
| | | package kr.wisestone.owl.domain; |
| | | |
| | | import org.hibernate.annotations.DynamicInsert; |
| | | import org.hibernate.annotations.DynamicUpdate; |
| | | |
| | | import javax.persistence.*; |
| | | import java.io.Serializable; |
| | | import java.util.HashSet; |
| | |
| | | * Created by wisestone on 2018-01-03. |
| | | */ |
| | | @Entity |
| | | @DynamicInsert |
| | | @DynamicUpdate |
| | | public class Issue extends BaseEntity implements Serializable { |
| | | private static final long serialVersionUID = 1L; |
| | | public static final String WORKSPACE_MANAGER = "WORKSPACE_MANAGER"; // 업무 공간 관리자 |
| | |
| | | public static final String REGISTER = "REGISTER"; // 이슈 등록자 |
| | | public static final String ASSIGNEE = "ASSIGNEE"; // 이슈 담당자 |
| | | public static final String DEPARTMENT = "DEPARTMENT"; // 이슈 담당부서 |
| | | |
| | | public static final String IS_API_YES = "Y"; |
| | | public static final String IS_API_NO = "N"; |
| | | |
| | | @Id |
| | | @GeneratedValue(strategy = GenerationType.IDENTITY) |
| | |
| | | private Long issueNumber; |
| | | private String startDate; |
| | | private String completeDate; |
| | | private String isApi; |
| | | |
| | | @ManyToOne(fetch=FetchType.LAZY) |
| | | @JoinColumn(name = "project_id") |
| | |
| | | public void setParentIssue(Issue parentIssue) { |
| | | this.parentIssue = parentIssue; |
| | | } |
| | | |
| | | public String isApi() { |
| | | return isApi; |
| | | } |
| | | |
| | | public void setApi(String api) { |
| | | isApi = api; |
| | | } |
| | | } |
| | |
| | | package kr.wisestone.owl.mapper; |
| | | |
| | | import kr.wisestone.owl.web.condition.IssueCondition; |
| | | import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition; |
| | | import kr.wisestone.owl.web.form.IssueForm; |
| | | import org.springframework.data.repository.query.Param; |
| | | import org.springframework.stereotype.Repository; |
| | |
| | | public interface IssueMapper { |
| | | List<Map<String, Object>> find(IssueCondition issueCondition); |
| | | |
| | | List<Map<String, Object>> findByCustomFieldValue(IssueCustomFieldValueCondition issueCustomFieldValueCondition); |
| | | |
| | | Long count(IssueCondition issueCondition); |
| | | |
| | | void insertBatch(@Param("issueForms") List<IssueForm> issueForms); |
| | |
| | | package kr.wisestone.owl.service; |
| | | |
| | | import kr.wisestone.owl.domain.ApiToken; |
| | | import kr.wisestone.owl.domain.CompanyField; |
| | | import kr.wisestone.owl.domain.CustomField; |
| | | import kr.wisestone.owl.domain.Event; |
| | | import kr.wisestone.owl.domain.*; |
| | | import kr.wisestone.owl.vo.ApiTokenVo; |
| | | import kr.wisestone.owl.vo.CompanyFieldVo; |
| | | import kr.wisestone.owl.vo.EventVo; |
| | | import kr.wisestone.owl.vo.UserVo; |
| | | import kr.wisestone.owl.web.condition.ApiTokenCondition; |
| | | import kr.wisestone.owl.web.condition.CompanyFieldCondition; |
| | | import kr.wisestone.owl.web.condition.EventCondition; |
| | |
| | | |
| | | ApiTokenVo find(); |
| | | |
| | | UserVo certification(String token); |
| | | |
| | | void remove(ApiTokenForm apiTokenForm); |
| | | } |
| | |
| | | |
| | | List<AttachedFile> addAttachedFile(List<MultipartFile> multipartFiles, Map<String, Object> content); |
| | | |
| | | List<AttachedFile> addAttachedFile(Workspace workspace, Issue issue, List<Map<String, Object>> files); |
| | | |
| | | List<AttachedFileVo> findAttachedFile(Map<String, Object> resJsonData, AttachedFileCondition condition); |
| | | |
| | | List<AttachedFile> findByIssueId(Long issueId); |
| | |
| | | import kr.wisestone.owl.web.form.IssueApiDefaultForm; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public interface CustomFieldApiOverlapService extends AbstractService<CustomFieldApiOverlap, Long, JpaRepository<CustomFieldApiOverlap, Long>> { |
| | | void find(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form); |
| | | List<CustomFieldApiOverlap> find(Long userId, Long issueTypeId); |
| | | boolean modify(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form); |
| | | } |
| | |
| | | |
| | | public interface IssueApiDefaultService extends AbstractService<IssueApiDefault, Long, JpaRepository<IssueApiDefault, Long>> { |
| | | IssueApiDefault find(Map<String, Object> resJsonData, IssueApiDefaultForm form); |
| | | IssueApiDefault find(IssueApiDefaultForm form); |
| | | boolean modify(Map<String, Object> resJsonData, IssueApiDefaultForm form); |
| | | } |
| | |
| | | import kr.wisestone.owl.domain.enumType.CustomFieldType; |
| | | import kr.wisestone.owl.vo.IssueCustomFieldValueVo; |
| | | import kr.wisestone.owl.web.condition.IssueCondition; |
| | | import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | |
| | | import java.util.List; |
| | |
| | | |
| | | boolean find(IssueCondition condition, Set<String> issueIds); |
| | | |
| | | Map<String, Object> find(IssueCustomFieldValueCondition issueCustomFieldValueCondition); |
| | | |
| | | List<Map<String, Object>> findInIssueIds(IssueCondition issueCondition); |
| | | |
| | | void removeIssueCustomFieldValuesByCustomFieldId(CustomField customField); |
| | |
| | | |
| | | import kr.wisestone.owl.domain.Issue; |
| | | import kr.wisestone.owl.domain.IssueDepartment; |
| | | import kr.wisestone.owl.domain.User; |
| | | import kr.wisestone.owl.domain.Workspace; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | | |
| | |
| | | //담당부서 |
| | | void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds); |
| | | |
| | | void modifyIssueDepartment(Issue issue, User user, Workspace workspace, List<Long> departmentIds); |
| | | |
| | | void insertIssueDepartment(List<Map<String, Long>> issueAssigneeMaps); |
| | | |
| | | void removeIssueDepartment(Long projectId, List<Long> excludeUserIds); |
| | |
| | | |
| | | void addIssueHistory(Issue issue, IssueHistoryType issueHistoryType, String issueChangeDescription); |
| | | |
| | | void addIssueHistory(Issue issue, User user, IssueHistoryType issueHistoryType, String issueChangeDescription); |
| | | |
| | | void makeDescription(StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription); |
| | | |
| | | void makeDescription(User user, StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription); |
| | | |
| | | void findIssueHistory(Map<String, Object> resJsonData, IssueHistoryCondition issueHistoryCondition); |
| | | |
| | | List<IssueHistoryVo> findIssueHistory(Long issueId); |
| | |
| | | |
| | | import kr.wisestone.owl.domain.Issue; |
| | | import kr.wisestone.owl.domain.IssueType; |
| | | import kr.wisestone.owl.domain.User; |
| | | import kr.wisestone.owl.domain.Workflow; |
| | | import kr.wisestone.owl.vo.IssueVo; |
| | | import kr.wisestone.owl.web.condition.IssueCondition; |
| | | import kr.wisestone.owl.web.condition.ProjectCondition; |
| | | import kr.wisestone.owl.web.form.IssueApiForm; |
| | | import kr.wisestone.owl.web.form.IssueForm; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.data.jpa.repository.JpaRepository; |
| | |
| | | |
| | | Issue addIssue(IssueForm issueForm, List<MultipartFile> files); |
| | | |
| | | Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles); |
| | | |
| | | Issue addApiIssue(IssueApiForm issueApiForm); |
| | | |
| | | |
| | | List<IssueVo> findIssue(Map<String, Object> resJsonData, |
| | | IssueCondition condition, Pageable pageable); |
| | | |
| | |
| | | |
| | | void checkUseWorkspace(); |
| | | |
| | | Workspace checkUseWorkspace(User user, Long workspaceId); |
| | | |
| | | ModelAndView checkUseExcelDownload(Model model); |
| | | |
| | | boolean checkUseTraffic(Long fileSize); |
| | |
| | | import io.jsonwebtoken.Jws; |
| | | import io.jsonwebtoken.Jwts; |
| | | import io.jsonwebtoken.SignatureAlgorithm; |
| | | import kr.wisestone.owl.constant.MsgConstants; |
| | | import kr.wisestone.owl.domain.ApiToken; |
| | | import kr.wisestone.owl.domain.User; |
| | | import kr.wisestone.owl.exception.OwlRuntimeException; |
| | | import kr.wisestone.owl.repository.ApiTokenRepository; |
| | | import kr.wisestone.owl.service.ApiTokenService; |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | |
| | | } |
| | | |
| | | //JWT 복호화 |
| | | public UserVo getUser(String jwt) { |
| | | private UserVo getUserVo(String jwt) { |
| | | |
| | | //결과값 = Claims |
| | | Jws<Claims> claims = decryption(jwt); |
| | | if (claims == null) |
| | | return null; |
| | | |
| | | ObjectMapper objectMapper = new ObjectMapper(); |
| | | //반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용 |
| | | return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class); |
| | | } |
| | | |
| | | private Jws<Claims> decryption(String jwt) { |
| | | //결과값 = Claims |
| | | Jws<Claims> claims = null; |
| | | |
| | |
| | | } catch (Exception e) { |
| | | log.debug(e.getMessage(), e); |
| | | } |
| | | |
| | | ObjectMapper objectMapper = new ObjectMapper(); |
| | | //반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용 |
| | | return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class); |
| | | return claims; |
| | | } |
| | | |
| | | |
| | | // 토큰 조회 |
| | | @Override |
| | |
| | | return null; |
| | | } |
| | | |
| | | // 토큰 사용자 인증 |
| | | @Override |
| | | public UserVo certification(String token) { |
| | | UserVo userVo = this.getUserVo(token); |
| | | if (userVo != null){ |
| | | return userVo; |
| | | } else { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.ERROR_TOKEN)); |
| | | } |
| | | } |
| | | |
| | | // 토큰 삭제 |
| | | @Override |
| | | public void remove(ApiTokenForm apiTokenForm) { |
| | |
| | | } |
| | | } |
| | | |
| | | // 첨부 파일을 등록한다. - API 에서 사용 |
| | | @Override |
| | | @Transactional |
| | | public List<AttachedFile> addAttachedFile(Workspace workspace, Issue issue, List<Map<String, Object>> files) { |
| | | if (workspace == null) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.WORKSPACE_NOT_EXIST)); |
| | | } |
| | | |
| | | if (issue == null) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST)); |
| | | } |
| | | |
| | | if (files != null && files.size() > 0) { |
| | | List<Map<String, Object>> convertFileMaps = Lists.newArrayList(); |
| | | |
| | | for (Map<String, Object> file : files) { |
| | | String fileName = MapUtil.getString(file, "fileName"); |
| | | String fileStr = MapUtil.getString(file, "file"); |
| | | String contentType = MapUtil.getString(file, "contentType"); |
| | | convertFileMaps.add(CommonUtil.makeFileMap(fileName, fileStr, contentType)); |
| | | } |
| | | |
| | | return this.addAttachedFiles(workspace, convertFileMaps, issue, null, AttachedType.SUMMER); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // 첨부 파일을 등록한다. - 이슈 생성, 수정에서 사용 |
| | | @Override |
| | | @Transactional |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<CustomFieldApiOverlap> find(Long userId, Long issueTypeId) { |
| | | return this.customFieldApiOverlapRepository.findByUserIdAndIssueTypeId(userId, issueTypeId); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public void find(Map<String, Object> resJsonData, CustomFieldApiOverlapForm form) { |
| | | UserVo userVo = this.webAppUtil.getLoginUser(); |
| | | List<CustomFieldApiOverlap> customFieldApiOverlaps = this.customFieldApiOverlapRepository.findByUserIdAndIssueTypeId(userVo.getId(), form.getIssueTypeId()); |
| | | List<CustomFieldApiOverlap> customFieldApiOverlaps = this.find(form.getUserId(), form.getIssueTypeId()); |
| | | if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) { |
| | | |
| | | List<CustomFieldApiOverlapVo> customFieldApiOverlapVos = Lists.newArrayList(); |
| | |
| | | @Override |
| | | @Transactional |
| | | public IssueApiDefault find(Map<String, Object> resJsonData, IssueApiDefaultForm form) { |
| | | UserVo userVo = this.webAppUtil.getLoginUser(); |
| | | List<IssueApiDefault> issueApiDefaults = this.issueApiDefaultRepository.findByUserIdAndIssueTypeId(userVo.getId(), form.getIssueTypeId()); |
| | | if (issueApiDefaults != null && issueApiDefaults.size() > 0) { |
| | | IssueApiDefault issueApiDefault = issueApiDefaults.get(0); |
| | | form.setUserId(this.webAppUtil.getLoginId()); |
| | | IssueApiDefault issueApiDefault = this.find(form); |
| | | if (issueApiDefault != null) { |
| | | IssueApiDefaultVo issueApiDefaultVo = ConvertUtil.copyProperties(issueApiDefault, IssueApiDefaultVo.class); |
| | | Project project = issueApiDefault.getProject(); |
| | | if (project != null) { |
| | |
| | | } |
| | | |
| | | resJsonData.put(Constants.RES_KEY_CONTENTS, issueApiDefaultVo); |
| | | return issueApiDefault; |
| | | } |
| | | return issueApiDefault; |
| | | } |
| | | |
| | | @Override |
| | | public IssueApiDefault find(IssueApiDefaultForm form) { |
| | | if (form.getUserId() != null && form.getIssueTypeId() != null) { |
| | | List<IssueApiDefault> issueApiDefaults = this.issueApiDefaultRepository.findByUserIdAndIssueTypeId(form.getUserId(), form.getIssueTypeId()); |
| | | if (issueApiDefaults != null && issueApiDefaults.size() > 0) { |
| | | return issueApiDefaults.get(0); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | |
| | | return customFieldSearch; |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> find(IssueCustomFieldValueCondition issueCustomFieldValueCondition) { |
| | | if (issueCustomFieldValueCondition.getUseValues().size() > 0 || !StringUtils.isEmpty(issueCustomFieldValueCondition.getUseValue())) { |
| | | issueCustomFieldValueCondition.setWorkspaceId(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId()); |
| | | |
| | | // 사용자 정의 필드 값 검색 시작 |
| | | Map<String, Object> result = new HashMap<>(); |
| | | |
| | | switch (CustomFieldType.valueOf(issueCustomFieldValueCondition.getCustomFieldType())) { |
| | | case INPUT: |
| | | result = this.issueCustomFieldValueMapper.findLikeUseValue(issueCustomFieldValueCondition); |
| | | break; |
| | | case MULTI_SELECT: |
| | | case SINGLE_SELECT: |
| | | result = this.issueCustomFieldValueMapper.findByUseValue(issueCustomFieldValueCondition); |
| | | break; |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // 이슈에서 저장한 사용자 정의 필드 값을 조회한다. |
| | | @Override |
| | | @Transactional(readOnly = true) |
| | |
| | | package kr.wisestone.owl.service.impl; |
| | | |
| | | import com.google.common.collect.Lists; |
| | | import kr.wisestone.owl.domain.Issue; |
| | | import kr.wisestone.owl.domain.IssueDepartment; |
| | | import kr.wisestone.owl.domain.IssueUser; |
| | | import kr.wisestone.owl.domain.Workspace; |
| | | import kr.wisestone.owl.domain.*; |
| | | import kr.wisestone.owl.mapper.IssueDepartmentMapper; |
| | | import kr.wisestone.owl.mapper.IssueUserMapper; |
| | | import kr.wisestone.owl.repository.IssueDepartmentRepository; |
| | |
| | | @Override |
| | | @Transactional |
| | | public void modifyIssueDepartment(Issue issue, Workspace workspace, List<Long> departmentIds) { |
| | | User user = this.webAppUtil.getLoginUserObject(); |
| | | modifyIssueDepartment(issue, user, workspace, departmentIds); |
| | | } |
| | | |
| | | // 이슈 담당부서를 변경한다. |
| | | @Override |
| | | @Transactional |
| | | public void modifyIssueDepartment(Issue issue, User user, Workspace workspace, List<Long> departmentIds) { |
| | | List<Long> oldDepartmentIds = Lists.newArrayList(); |
| | | |
| | | // 이전 담당 부서 |
| | |
| | | issueAssigneeMap.put("departmentId", departmentId); //담당부서 |
| | | issueAssigneeMap.put("issueId", issue.getId()); |
| | | issueAssigneeMap.put("workspaceId", workspace.getId()); |
| | | issueAssigneeMap.put("registerId", this.webAppUtil.getLoginId()); |
| | | issueAssigneeMap.put("modifyId", this.webAppUtil.getLoginId()); |
| | | issueAssigneeMap.put("registerId", user.getId()); |
| | | issueAssigneeMap.put("modifyId", user.getId()); |
| | | addIssueAssigneeMaps.add(issueAssigneeMap); |
| | | } |
| | | |
| | |
| | | @Override |
| | | @Transactional |
| | | public void addIssueHistory(Issue issue, IssueHistoryType issueHistoryType, String issueChangeDescription) { |
| | | User user = this.webAppUtil.getLoginUserObject(); |
| | | addIssueHistory(issue, user, issueHistoryType, issueChangeDescription); |
| | | } |
| | | |
| | | // 이력 생성 |
| | | @Override |
| | | @Transactional |
| | | public void addIssueHistory(Issue issue, User user, IssueHistoryType issueHistoryType, String issueChangeDescription) { |
| | | IssueHistory issueHistory = new IssueHistory(); |
| | | issueHistory.setIssue(issue); |
| | | issueHistory.setProject(issue.getProject()); |
| | | issueHistory.setIssueHistoryType(issueHistoryType); |
| | | StringBuilder description = new StringBuilder(); |
| | | // 이력 정보를 만들어 낸다. |
| | | this.makeDescription(description, issueHistoryType, issueChangeDescription); |
| | | |
| | | this.makeDescription(user, description, issueHistoryType, issueChangeDescription); |
| | | issueHistory.setDescription(description.toString()); |
| | | |
| | | this.issueHistoryRepository.saveAndFlush(issueHistory); |
| | |
| | | // 이력 정보를 만들어 낸다. |
| | | @Override |
| | | public void makeDescription(StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) { |
| | | User user = this.webAppUtil.getLoginUserObject(); |
| | | makeDescription(user, description, issueHistoryType, issueChangeDescription); |
| | | } |
| | | |
| | | // 이력 정보를 만들어 낸다. |
| | | @Override |
| | | public void makeDescription(User user, StringBuilder description, IssueHistoryType issueHistoryType, String issueChangeDescription) { |
| | | description.append("<div class=\"activity-text\">"); |
| | | |
| | | // 생성, 수정, 삭제에 대해 기록을 남긴다. |
| | |
| | | description.append("<span class='activity-timestamp'>"); |
| | | description.append(DateUtil.convertDateToStr(new Date())); |
| | | description.append(" ("); |
| | | description.append(this.webAppUtil.getLoginUser().getName()); |
| | | description.append(user.getName()); |
| | | description.append(" - "); |
| | | description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount())); |
| | | description.append(CommonUtil.decryptAES128(user.getAccount())); |
| | | description.append(")"); |
| | | description.append("</span></h6>"); |
| | | break; |
| | |
| | | description.append(DateUtil.convertDateToStr(new Date())); |
| | | description.append(" ("); |
| | | |
| | | if (this.webAppUtil.getLoginUser() != null) { |
| | | description.append(this.webAppUtil.getLoginUser().getName()); |
| | | if (user != null) { |
| | | description.append(user.getName()); |
| | | description.append(" - "); |
| | | description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount())); |
| | | description.append(CommonUtil.decryptAES128(user.getAccount())); |
| | | } |
| | | else { |
| | | description.append("OWL-ITS-SYSTEM"); |
| | |
| | | description.append("<span class=\"activity-timestamp\">"); |
| | | description.append(DateUtil.convertDateToStr(new Date())); |
| | | description.append(" ("); |
| | | description.append(this.webAppUtil.getLoginUser().getName()); |
| | | description.append(user.getName()); |
| | | description.append(" - "); |
| | | description.append(CommonUtil.decryptAES128(this.webAppUtil.getLoginUser().getAccount())); |
| | | description.append(CommonUtil.decryptAES128(user.getAccount())); |
| | | description.append(")"); |
| | | description.append("</span></h6>"); |
| | | break; |
| | |
| | | import kr.wisestone.owl.util.DateUtil; |
| | | import kr.wisestone.owl.vo.*; |
| | | import kr.wisestone.owl.web.condition.IssueCondition; |
| | | import kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition; |
| | | import kr.wisestone.owl.web.condition.IssueTypeCustomFieldCondition; |
| | | import kr.wisestone.owl.web.condition.ProjectCondition; |
| | | import kr.wisestone.owl.web.form.IssueCommentForm; |
| | | import kr.wisestone.owl.web.form.IssueForm; |
| | | import kr.wisestone.owl.web.form.*; |
| | | import kr.wisestone.owl.web.view.ExcelView; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.commons.lang3.time.StopWatch; |
| | |
| | | |
| | | @Autowired |
| | | private SeverityService severityService; |
| | | |
| | | @Autowired |
| | | private CustomFieldApiOverlapService customFieldApiOverlapService; |
| | | |
| | | @Autowired |
| | | private IssueApiDefaultService issueApiDefaultService; |
| | | |
| | | @Autowired |
| | | private ApiTokenService apiTokenService; |
| | | |
| | | @Autowired |
| | | private CompanyFieldService companyFieldService; |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | // API 를 통해 이슈 추가. |
| | | @Override |
| | | @Transactional |
| | | public Issue addApiIssue(IssueApiForm issueApiForm) { |
| | | if (issueApiForm.getIssueTypeId() == null) { |
| | | throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR)); |
| | | } |
| | | |
| | | IssueForm issueForm = ConvertUtil.copyProperties(issueApiForm, IssueForm.class); |
| | | // issueForm.setFiles(issueApiForm.getFiles()); |
| | | IssueType issueType = this.issueTypeService.getIssueType(issueApiForm.getIssueTypeId()); |
| | | if (issueType == null){ |
| | | throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_ISSUE_TYPE_ERROR)); |
| | | } |
| | | |
| | | // 프로젝트 입력 |
| | | Project project = issueType.getProject(); |
| | | if (project == null){ |
| | | throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_PARAMETER_PROJECT_ERROR)); |
| | | } |
| | | issueForm.setProjectId(project.getId()); |
| | | |
| | | // 토큰으로 유저 정보 가져오기 |
| | | String token = issueApiForm.getToken(); |
| | | UserVo userVo = this.apiTokenService.certification(token); |
| | | |
| | | // 해당 유저 정보가 현재 db에 있는지 확인 |
| | | User user = this.userService.getUser(userVo.getId()); |
| | | if (user != null) { |
| | | |
| | | // 기본값 입력하기 |
| | | IssueApiDefaultForm issueApiDefaultForm = new IssueApiDefaultForm(); |
| | | issueApiDefaultForm.setUserId(user.getId()); |
| | | issueApiDefaultForm.setIssueTypeId(issueForm.getIssueTypeId()); |
| | | IssueApiDefault issueApiDefault = this.issueApiDefaultService.find(issueApiDefaultForm); |
| | | if (issueApiDefault != null) { |
| | | ConvertUtil.copyProperties(issueApiDefault, issueForm); |
| | | issueForm.setPriorityId(issueApiDefault.getPriority().getId()); |
| | | issueForm.setSeverityId(issueApiDefault.getSeverity().getId()); |
| | | } |
| | | |
| | | // 중복 값 하위 이슈로 처리하기 |
| | | CustomFieldApiOverlapForm customFieldApiOverlapForm = new CustomFieldApiOverlapForm(); |
| | | customFieldApiOverlapForm.setUserId(user.getId()); |
| | | customFieldApiOverlapForm.setIssueTypeId(issueForm.getIssueTypeId()); |
| | | |
| | | IssueVo issueVo = this.findIssue(issueApiForm, user.getId()); |
| | | if (issueVo != null) { |
| | | issueForm.setParentIssueId(issueVo.getId()); |
| | | } |
| | | |
| | | issueForm.setIsApi(Issue.IS_API_YES); |
| | | |
| | | // 사용자 정의 필드 설정 |
| | | issueForm.setIssueCustomFields(issueApiForm.getCustomFieldValues()); |
| | | |
| | | // api 입력값 적용 |
| | | ConvertUtil.copyProperties(issueApiForm, issueForm); |
| | | |
| | | return addIssue(user, issueForm, issueApiForm.getMultipartFiles()); |
| | | } else { |
| | | throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_USER_ERROR)); |
| | | } |
| | | } |
| | | |
| | | // 중복된 상위 이슈 검색 |
| | | private IssueVo findIssue(IssueApiForm issueApiForm, Long userId) { |
| | | IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition(); |
| | | |
| | | List<CustomFieldApiOverlap> customFieldApiOverlaps = this.customFieldApiOverlapService.find(userId, issueApiForm.getIssueTypeId()); |
| | | if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) { |
| | | for (CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) { |
| | | for (IssueCustomFieldValueForm issueCustomFieldValue : issueApiForm.getIssueCustomFieldValues()) { |
| | | if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValue.getCustomFieldId())) { |
| | | issueCustomFieldValueCondition.addUseValues(issueCustomFieldValue.getUseValue()); |
| | | } |
| | | } |
| | | } |
| | | List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); |
| | | if (results != null && results.size() > 0) { |
| | | IssueVo issueVo = new IssueVo(); |
| | | ConvertUtil.convertMapToObject(results.get(0), issueVo); |
| | | return issueVo; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // 이슈를 생성한다. |
| | | @Override |
| | | @Transactional |
| | | public Issue addIssue(IssueForm issueForm, List<MultipartFile> multipartFiles) { |
| | | User user = this.webAppUtil.getLoginUserObject(); |
| | | return addIssue(user, issueForm, multipartFiles); |
| | | } |
| | | |
| | | // 이슈를 생성한다. |
| | | @Override |
| | | @Transactional |
| | | public Issue addIssue(User user, IssueForm issueForm, List<MultipartFile> multipartFiles) { |
| | | // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. |
| | | this.workspaceService.checkUseWorkspace(); |
| | | Workspace workspace = this.workspaceService.checkUseWorkspace(user, user.getLastWorkspaceId()); |
| | | // 프로젝트 유효성 체크 |
| | | Project project = this.projectService.getProject(issueForm.getProjectId()); |
| | | // 이슈 유형 유효성 체크 |
| | |
| | | |
| | | issue.setIssueNumber(this.issueNumberGeneratorService.generateIssueNumber(project)); // 각 프로젝트의 고유 이슈 번호 생성 |
| | | |
| | | this.issueRepository.saveAndFlush(issue); |
| | | issue = this.issueRepository.saveAndFlush(issue); |
| | | |
| | | issue.setReverseIndex(issue.getId() * -1); // 쿼리 속도 개선을 위해 리버스 인덱스 생성 |
| | | // 담당자 지정 |
| | |
| | | // HOSTING 정보 저장 |
| | | this.issueHostingService.modifyIssueHostingField(issue, issueForm.getIssueHostingFields()); |
| | | |
| | | |
| | | // 첨부 파일 저장 |
| | | // multipartFile 을 file Map List 객체로 변경한다. |
| | | List<Map<String, Object>> convertFileMaps = this.convertMultipartFileToFile(multipartFiles); |
| | | // 첨부 파일 저장 |
| | | this.attachedFileService.addAttachedFile(convertFileMaps, issue, this.webAppUtil.getLoginUser().getAccount()); |
| | | this.attachedFileService.addAttachedFile(convertFileMaps, issue, user.getAccount()); |
| | | |
| | | // 텍스트 에디터에 첨부한 파일을 이슈와 연결 |
| | | this.checkNotHaveIssueIdAttachedFile(issue, issueForm); |
| | | // 사용자 정의 필드 저장 |
| | | this.issueCustomFieldValueService.modifyIssueCustomFieldValue(issue, issueForm.getIssueCustomFields()); |
| | | // 이슈 이력 생성 |
| | | this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.ADD, null); |
| | | this.issueHistoryService.addIssueHistory(issue, user, IssueHistoryType.ADD, null); |
| | | // 이슈 위험 관리 생성 |
| | | this.issueRiskService.addIssueRisk(issue, project.getWorkspace()); |
| | | // 영속성 컨텍스트 비우기 |
| | | this.clear(); |
| | | // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. |
| | | this.reservationIssueEmail(issue.getId(), EmailType.ISSUE_ADD); |
| | | this.reservationIssueEmail(issue, EmailType.ISSUE_ADD); |
| | | // 사용자 시스템 기능 사용 정보 수집 |
| | | log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ADD)); |
| | | |
| | | UserVo userVo = ConvertUtil.copyProperties(user, UserVo.class); |
| | | log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(userVo, ElasticSearchConstants.ISSUE_ADD)); |
| | | |
| | | return issue; |
| | | } |
| | | |
| | | // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. |
| | | private void reservationIssueEmail(Long id, EmailType emailType) { |
| | | Issue issue = this.getIssue(id); |
| | | |
| | | private void reservationIssueEmail(Issue issue, EmailType emailType) { |
| | | Map<String, Object> issueMap = new HashMap<>(); |
| | | // 이슈 정보를 이메일 전송에 사용하기 위해 Map 형태로 변환한다. |
| | | this.makeIssueMapToIssue(issue, issueMap); |
| | |
| | | |
| | | case "02": // 프로젝트, 이슈 유형, 이슈 상태, 우선순위, 중요도, 담당자, 첨부파일, 사용자 정의 필드 정보, 댓글, 기록을 셋팅한다. |
| | | this.setIssueDetail(issueVo, issue); // 이슈 상세 정보를 셋팅한다. |
| | | issueVo.setProjectVo(ConvertUtil.copyProperties(issue.getProject(), ProjectVo.class)); |
| | | break; |
| | | } |
| | | } |
| | |
| | | private List<Map<String, Object>> convertMultipartFileToFile(List<MultipartFile> multipartFiles) { |
| | | List<Map<String, Object>> convertFileMaps = Lists.newArrayList(); |
| | | |
| | | for (MultipartFile multipartFile : multipartFiles) { |
| | | try { |
| | | Map<String, Object> fileMap = CommonUtil.makeFileMap(multipartFile); |
| | | convertFileMaps.add(fileMap); |
| | | } catch (Exception e) { |
| | | log.debug("multipartFile -> file 변환 오류" + e.getMessage()); |
| | | if (multipartFiles != null && multipartFiles.size() > 0) { |
| | | for (MultipartFile multipartFile : multipartFiles) { |
| | | try { |
| | | Map<String, Object> fileMap = CommonUtil.makeFileMap(multipartFile); |
| | | convertFileMaps.add(fileMap); |
| | | } catch (Exception e) { |
| | | log.debug("multipartFile -> file 변환 오류" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // 이슈 생성, 삭제시 예약 이메일에 등록해놓는다. |
| | | this.reservationIssueEmail(issue.getId(), EmailType.ISSUE_REMOVE); |
| | | this.reservationIssueEmail(issue, EmailType.ISSUE_REMOVE); |
| | | // 이슈 삭제 |
| | | this.issueRepository.delete(issue); |
| | | |
| | |
| | | public void reservationIssue() { |
| | | List<IssueReservation> issueReservations = this.issueReservationService.findByIssueReservationTypeNotNull(); |
| | | |
| | | |
| | | Calendar calendar = Calendar.getInstance(); |
| | | int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); |
| | | int month = calendar.get(Calendar.MONTH) + 1; |
| | |
| | | @Override |
| | | public void modifyParentIssue(IssueForm issueDownForm) { |
| | | Issue issue = this.getIssue(issueDownForm.getId()); //하위 이슈 |
| | | Long newParentIssueId = issueDownForm.getParentIssueId(); //변경할 하위이슈의 상위이슈 |
| | | |
| | | StringBuilder sb = new StringBuilder(); |
| | | |
| | | Issue parentIssue = issue.getParentIssue(); //변경 전 하위이슈의 상위이슈 |
| | | if(parentIssue != null){ //변경 전 하위이슈의 상위이슈가 존재 할 경우 |
| | | this.issueHistoryService.detectDownIssues(IssueHistoryType.DELETE, issue, sb); |
| | | this.issueHistoryService.addIssueHistory(parentIssue, IssueHistoryType.MODIFY, sb.toString()); |
| | | } |
| | | |
| | | Long newParentIssueId = issueDownForm.getParentIssueId(); //변경할 하위이슈의 상위이슈 |
| | | StringBuilder sb = new StringBuilder(); |
| | | |
| | | if (newParentIssueId != null) { // 추가 할 경우 |
| | | parentIssue = this.getIssue(newParentIssueId); //상위이슈(myIssue) |
| | |
| | | @Override |
| | | @Transactional |
| | | public void checkUseWorkspace() { |
| | | Workspace workspace = this.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId()); |
| | | User user = this.webAppUtil.getLoginUserObject(); |
| | | Workspace workspace = this.getWorkspace(user.getLastWorkspaceId()); |
| | | |
| | | this.checkUseWorkspace(user, workspace.getId()); |
| | | } |
| | | |
| | | // 사용하고 있는 업무 공간이 활성 상태인지 확인한다. 사용 공간에서 로그인한 사용자가 비활성인지 확인한다. |
| | | @Override |
| | | @Transactional |
| | | public Workspace checkUseWorkspace(User user, Long workspaceId) { |
| | | if (user == null) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.USER_NOT_EXIST)); |
| | | } |
| | | |
| | | if (workspaceId == null) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.WORKSPACE_NOT_EXIST)); |
| | | } |
| | | |
| | | Workspace workspace = this.getWorkspace(workspaceId); |
| | | |
| | | if (workspace.getServiceType().equals(ServiceType.UNUSED)) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.WORKSPACE_USE_PERIOD_EXCESS)); |
| | | } |
| | | |
| | | UserWorkspace userWorkspace = this.userWorkspaceService.findByUserIdAndWorkspaceId(this.webAppUtil.getLoginId(), workspace.getId()); |
| | | UserWorkspace userWorkspace = this.userWorkspaceService.findByUserIdAndWorkspaceId(user.getId(), workspace.getId()); |
| | | |
| | | if (!userWorkspace.getUseYn()) { |
| | | // 해당 사용자가 관리하는 업무 공간를 마지막 접근 업무 공간로 변경한다. |
| | | this.userService.updateLastMyWorkspace(userWorkspace.getUser()); |
| | | |
| | | // 비활성 사용자는 더이상 해당 업무 공간에 있으면 안된다. |
| | | this.simpMessagingTemplate.convertAndSendToUser(this.webAppUtil.getLoginUser().getAccount(), "/notification/workspace-remove", this.messageAccessor.getMessage(MsgConstants.WORKSPACE_OUT, workspace.getName())); |
| | | this.simpMessagingTemplate.convertAndSendToUser(user.getAccount(), "/notification/workspace-remove", this.messageAccessor.getMessage(MsgConstants.WORKSPACE_OUT, workspace.getName())); |
| | | |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.WORKSPACE_INCLUDE_DISABLED)); |
| | | } |
| | | |
| | | return workspace; |
| | | } |
| | | |
| | | // 사용 공간에서 로그인한 사용자가 비활성인지 확인하고 비활성일 경우 엑셀 다운로드를 금지한다. |
| | |
| | | return fileMap; |
| | | } |
| | | |
| | | // string file 정보를 file Map 형태로 변경한다. |
| | | public static Map<String, Object> makeFileMap(String fileName, String file, String contentType) { |
| | | Map<String, Object> fileMap = new HashMap<>(); |
| | | |
| | | try { |
| | | byte[] bytes = Base64.decodeBase64(file); |
| | | |
| | | fileMap.put("fileName", fileName); |
| | | fileMap.put("fileSize", bytes.length); |
| | | fileMap.put("contentType", contentType); |
| | | fileMap.put("file", CommonUtil.bytesToFile(fileName, bytes)); |
| | | } catch (Exception e) { |
| | | LOGGER.debug(e.getMessage()); |
| | | } |
| | | |
| | | return fileMap; |
| | | } |
| | | |
| | | public static String getPostDataString(Map<String, String> params) throws UnsupportedEncodingException { |
| | | StringBuilder result = new StringBuilder(); |
| | | boolean first = true; |
| | |
| | | return convertFile; |
| | | } |
| | | |
| | | // string을 파일로 변환 |
| | | public static File stringToFile(String fileName, String file) { |
| | | |
| | | byte[] bytes = null; |
| | | try { |
| | | bytes = Base64.decodeBase64(file); |
| | | |
| | | } catch (Exception ex) { |
| | | LOGGER.debug("string to bytes 변환 오류"); |
| | | } |
| | | |
| | | if (bytes != null) { |
| | | return bytesToFile(fileName, bytes); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // bytes를 파일로 변환 |
| | | public static File bytesToFile(String fileName, byte[] bytes) { |
| | | File convertFile = new File(WebAppUtil.getContextRealPath() + TMP_UPLOAD_FOLDER + getFileNameByUUID(fileName)); |
| | | if (!convertFile.exists()) { |
| | | convertFile.mkdirs(); |
| | | } |
| | | |
| | | try{ |
| | | FileOutputStream lFileOutputStream = new FileOutputStream(convertFile); |
| | | lFileOutputStream.write(bytes); |
| | | lFileOutputStream.close(); |
| | | |
| | | }catch (IllegalStateException | IOException e) { |
| | | LOGGER.debug("bytes 파일 file 변환 오류"); |
| | | } |
| | | |
| | | return convertFile; |
| | | } |
| | | |
| | | public static InputStream getFileInputStream(String strPath, String strNewFileName){ |
| | | InputStream objInputStream = null; |
| | | |
| | |
| | | package kr.wisestone.owl.web.controller; |
| | | |
| | | import kr.wisestone.owl.constant.Constants; |
| | | import kr.wisestone.owl.domain.Issue; |
| | | import kr.wisestone.owl.exception.OwlRuntimeException; |
| | | import kr.wisestone.owl.service.GuideService; |
| | | import kr.wisestone.owl.service.IssueService; |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.util.MapUtil; |
| | | import kr.wisestone.owl.web.condition.GuideCondition; |
| | | import kr.wisestone.owl.web.form.GuideForm; |
| | | import kr.wisestone.owl.web.form.IssueApiForm; |
| | | import kr.wisestone.owl.web.form.IssueForm; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.domain.Pageable; |
| | | import org.springframework.http.MediaType; |
| | |
| | | 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.multipart.MultipartHttpServletRequest; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.Stack; |
| | | |
| | | @Controller |
| | | public class ApiController extends BaseController { |
| | | |
| | | @Autowired |
| | | private GuideService guideService; |
| | | private IssueService issueService; |
| | | |
| | | // 이슈 추가 |
| | | @RequestMapping(value = "api/issue", produces = MediaType.APPLICATION_JSON_VALUE) |
| | | // 이슈 추가(json 방식으로 파일전송) |
| | | // @RequestMapping(value = "api/issue", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) |
| | | // public |
| | | // @ResponseBody |
| | | // Map<String, Object> addIssue(@RequestBody Map<String, Map<String, Object>> params) { |
| | | // Map<String, Object> resJsonData = new HashMap<>(); |
| | | // |
| | | // IssueApiForm issueForm = IssueApiForm.make(params.get(Constants.REQ_KEY_CONTENT)); |
| | | // Issue issue = this.issueService.addApiIssue(issueForm); |
| | | // // 버전 생성 |
| | | // this.issueService.addIssueVersion(issue.getId()); |
| | | // return this.setSuccessMessage(resJsonData); |
| | | // } |
| | | @RequestMapping(value = "api/issue", method = RequestMethod.POST) |
| | | public |
| | | @ResponseBody |
| | | Map<String, Object> add(@RequestBody Map<String, Map<String, Object>> params) { |
| | | Map<String, Object> addIssue(MultipartHttpServletRequest request) throws OwlRuntimeException { |
| | | Map<String, Object> resJsonData = new HashMap<>(); |
| | | |
| | | // todo |
| | | |
| | | IssueApiForm issueForm = IssueApiForm.make(ConvertUtil.convertJsonToMap(request.getParameter(Constants.REQ_KEY_CONTENT)), request.getFiles("file")); |
| | | Issue issue = this.issueService.addApiIssue(issueForm); |
| | | // 버전 생성 |
| | | this.issueService.addIssueVersion(issue.getId()); |
| | | return this.setSuccessMessage(resJsonData); |
| | | } |
| | | |
| | | // 이슈 조회 |
| | | @RequestMapping(value = "/api/issuelist", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) |
| | | @RequestMapping(value = "/api/issueList", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) |
| | | public |
| | | @ResponseBody |
| | | Map<String, Object> find(@RequestBody Map<String, Map<String, Object>> params) { |
| | |
| | | Map<String, Object> resJsonData = new HashMap<>(); |
| | | Pageable pageable = this.pageUtil.convertPageable(this.getPageVo(params)); |
| | | |
| | | this.issueService.findMailTargetAll(resJsonData, IssueCondition.make(params.get(Constants.REQ_KEY_CONTENT)), pageable); |
| | | // this.issueService.findMailTargetAll(resJsonData, IssueCondition.make(params.get(Constants.REQ_KEY_CONTENT)), pageable); |
| | | |
| | | return this.setSuccessMessage(resJsonData); |
| | | }*/ |
New file |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | public class CustomFieldValueForm { |
| | | private Long customFieldId; |
| | | private String value; |
| | | |
| | | public CustomFieldValueForm(){} |
| | | |
| | | public Long getCustomFieldId() { |
| | | return customFieldId; |
| | | } |
| | | |
| | | public void setCustomFieldId(Long customFieldId) { |
| | | this.customFieldId = customFieldId; |
| | | } |
| | | |
| | | public String getValue() { |
| | | return value; |
| | | } |
| | | |
| | | public void setValue(String value) { |
| | | this.value = value; |
| | | } |
| | | } |
New file |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | import com.google.common.collect.Lists; |
| | | import kr.wisestone.owl.domain.IssueCustomFieldValue; |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.util.MapUtil; |
| | | import kr.wisestone.owl.vo.CustomFieldVo; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.util.*; |
| | | |
| | | public class IssueApiForm { |
| | | private String token; |
| | | private String title; |
| | | private String projectKey; |
| | | private String description; |
| | | private Long issueTypeId; |
| | | private Long priorityId; |
| | | private Long severityId; |
| | | private Date startDate; |
| | | private Date endDate; |
| | | private Date searchTime; |
| | | private List<DepartmentForm> departments = Lists.newArrayList(); |
| | | private List<IssueCustomFieldValueForm> issueCustomFieldValues = Lists.newArrayList(); |
| | | private List<Map<String, Object>> CustomFieldValues = Lists.newArrayList(); |
| | | // private List<Map<String, Object>> files = Lists.newArrayList(); |
| | | private List<MultipartFile> multipartFiles = Lists.newArrayList(); |
| | | |
| | | public IssueApiForm() { |
| | | } |
| | | |
| | | public static IssueApiForm make(Map<String, Object> content, List<MultipartFile> files) { |
| | | IssueApiForm form = ConvertUtil.convertMapToClass(content, IssueApiForm.class); |
| | | form.setMultipartFiles(files); |
| | | |
| | | // 사용자 필드 정보 |
| | | if (MapUtil.getObject(content, "customFields") != null){ |
| | | List<Map<String, Object>> customFields = (List)MapUtil.getObject(content, "customFields"); |
| | | for (Map<String, Object> customField : customFields) { |
| | | IssueCustomFieldValueForm issueCustomFieldValueForm = ConvertUtil.convertMapToClass(customField, IssueCustomFieldValueForm.class); |
| | | form.addIssueCustomFieldValue(issueCustomFieldValueForm); |
| | | |
| | | |
| | | Map<String, Object> customFieldVo = new HashMap<>(); |
| | | customFieldVo.put("id", issueCustomFieldValueForm.getCustomFieldId()); |
| | | |
| | | customField.put("customFieldVo", customFieldVo); |
| | | |
| | | List<String> useValues = Lists.newArrayList(); |
| | | useValues.add(issueCustomFieldValueForm.getUseValue()); |
| | | customField.put("useValues", useValues); |
| | | |
| | | form.addCustomFieldValue(customField); |
| | | } |
| | | } |
| | | |
| | | // 첨부 파일 |
| | | // if (MapUtil.getObject(content, "files") != null){ |
| | | // form.setFiles((List)MapUtil.getObject(content, "files")); |
| | | // } |
| | | return form; |
| | | } |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public void setToken(String token) { |
| | | this.token = token; |
| | | } |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public void setTitle(String title) { |
| | | this.title = title; |
| | | } |
| | | |
| | | public String getProjectKey() { |
| | | return projectKey; |
| | | } |
| | | |
| | | public void setProjectKey(String projectKey) { |
| | | this.projectKey = projectKey; |
| | | } |
| | | |
| | | public String getDescription() { |
| | | return description; |
| | | } |
| | | |
| | | public void setDescription(String description) { |
| | | this.description = description; |
| | | } |
| | | |
| | | public Long getIssueTypeId() { |
| | | return issueTypeId; |
| | | } |
| | | |
| | | public void setIssueTypeId(Long issueTypeId) { |
| | | this.issueTypeId = issueTypeId; |
| | | } |
| | | |
| | | public Long getPriorityId() { |
| | | return priorityId; |
| | | } |
| | | |
| | | public void setPriorityId(Long priorityId) { |
| | | this.priorityId = priorityId; |
| | | } |
| | | |
| | | public Long getSeverityId() { |
| | | return severityId; |
| | | } |
| | | |
| | | public void setSeverityId(Long severityId) { |
| | | this.severityId = severityId; |
| | | } |
| | | |
| | | public List<DepartmentForm> getDepartments() { |
| | | return departments; |
| | | } |
| | | |
| | | public void setDepartments(List<DepartmentForm> departments) { |
| | | this.departments = departments; |
| | | } |
| | | |
| | | public Date getStartDate() { |
| | | return startDate; |
| | | } |
| | | |
| | | public void setStartDate(Date startDate) { |
| | | this.startDate = startDate; |
| | | } |
| | | |
| | | public Date getEndDate() { |
| | | return endDate; |
| | | } |
| | | |
| | | public void setEndDate(Date endDate) { |
| | | this.endDate = endDate; |
| | | } |
| | | |
| | | public Date getSearchTime() { |
| | | return searchTime; |
| | | } |
| | | |
| | | public void setSearchTime(Date searchTime) { |
| | | this.searchTime = searchTime; |
| | | } |
| | | |
| | | public List<IssueCustomFieldValueForm> getIssueCustomFieldValues() { |
| | | return issueCustomFieldValues; |
| | | } |
| | | |
| | | public void setIssueCustomFieldValues(List<IssueCustomFieldValueForm> issueCustomFieldValues) { |
| | | this.issueCustomFieldValues = issueCustomFieldValues; |
| | | } |
| | | |
| | | public void addIssueCustomFieldValue(IssueCustomFieldValueForm issueCustomFieldValueForm) { |
| | | if (this.issueCustomFieldValues != null) { |
| | | this.issueCustomFieldValues.add(issueCustomFieldValueForm); |
| | | } |
| | | } |
| | | |
| | | public void addCustomFieldValue(Map<String, Object> map) { |
| | | if (this.CustomFieldValues != null) { |
| | | this.CustomFieldValues.add(map); |
| | | } |
| | | } |
| | | |
| | | public List<Map<String, Object>> getCustomFieldValues() { |
| | | return CustomFieldValues; |
| | | } |
| | | |
| | | public void setCustomFieldValues(List<Map<String, Object>> customFieldValues) { |
| | | CustomFieldValues = customFieldValues; |
| | | } |
| | | |
| | | // public List<Map<String, Object>> getFiles() { |
| | | // return files; |
| | | // } |
| | | // |
| | | // public void setFiles(List<Map<String, Object>> files) { |
| | | // this.files = files; |
| | | // } |
| | | |
| | | public List<MultipartFile> getMultipartFiles() { |
| | | return multipartFiles; |
| | | } |
| | | |
| | | public void setMultipartFiles(List<MultipartFile> multipartFiles) { |
| | | this.multipartFiles = multipartFiles; |
| | | } |
| | | } |
New file |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | public class IssueCustomFieldValueForm { |
| | | private Long customFieldId; |
| | | private String useValue; |
| | | |
| | | public IssueCustomFieldValueForm(){} |
| | | |
| | | public Long getCustomFieldId() { |
| | | return customFieldId; |
| | | } |
| | | |
| | | public void setCustomFieldId(Long customFieldId) { |
| | | this.customFieldId = customFieldId; |
| | | } |
| | | |
| | | public String getUseValue() { |
| | | return useValue; |
| | | } |
| | | |
| | | public void setUseValue(String useValue) { |
| | | this.useValue = useValue; |
| | | } |
| | | } |
| | |
| | | private List<Map<String, Object>> issueCompanyFields = Lists.newArrayList(); |
| | | private List<Map<String, Object>> issueIspFields = Lists.newArrayList(); |
| | | private List<Map<String, Object>> issueHostingFields = Lists.newArrayList(); |
| | | private List<Map<String, Object>> files = Lists.newArrayList(); // api용 첨부파일 |
| | | private Long parentIssueId; // 상위 이슈 |
| | | private String isApi; |
| | | |
| | | public IssueForm() { |
| | | } |
| | |
| | | // HOSTING 필드 정보 |
| | | if (MapUtil.getObject(params, "issueHostingFields") != null){ |
| | | form.setIssueHostingFields((List)MapUtil.getObject(params, "issueHostingFields")); |
| | | } |
| | | |
| | | // api 첨부파일 |
| | | if (MapUtil.getObject(params, "files") != null){ |
| | | form.setFiles((List)MapUtil.getObject(params, "files")); |
| | | } |
| | | return form; |
| | | } |
| | |
| | | this.parentIssueId = parentIssueId; |
| | | } |
| | | |
| | | public String getIsApi() { |
| | | return isApi; |
| | | } |
| | | |
| | | public void setIsApi(String isApi) { |
| | | this.isApi = isApi; |
| | | } |
| | | |
| | | public List<Map<String, Object>> getFiles() { |
| | | return files; |
| | | } |
| | | |
| | | public void setFiles(List<Map<String, Object>> files) { |
| | | this.files = files; |
| | | } |
| | | |
| | | public String getTemplate() { |
| | | return template; |
| | | } |
| | |
| | | Map<String, Object> resJsonData = new HashMap<String, Object>(); |
| | | resJsonData.put(Constants.RES_KEY_MESSAGE, this.messageAccessor.getResMessage(ex, Constants.RES_KEY_MSG_FAIL)); |
| | | |
| | | return this.handleExceptionInternal(ex, resJsonData, new HttpHeaders(), HttpStatus.OK, request); |
| | | return this.handleExceptionInternal(ex, resJsonData, new HttpHeaders(), HttpStatus.BAD_REQUEST, request); |
| | | } |
| | | |
| | | @ExceptionHandler({ StackOverflowError.class, |
| | |
| | | |
| | | -- issue_type 테이블 업체,ISP,호스팅 컬럼 추가 |
| | | ALTER TABLE `issue_type` ADD COLUMN `use_partner` BIGINT(11) NOT NULL DEFAULT '0'; |
| | | |
| | | -- api 이슈 여부 |
| | | ALTER TABLE `issue` ADD COLUMN `is_api` VARCHAR(1) NOT NULL DEFAULT 'N'; |
| | |
| | | issue WHERE issue_status_id = #{issueStatusId}; |
| | | </select> |
| | | |
| | | <!-- 특정 사용자 정의 필드 값이 같은 이슈를 조회 --> |
| | | <select id="findByCustomFieldValue" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition"> |
| | | SELECT |
| | | id |
| | | FROM issue |
| | | LEFT OUTER JOIN issue_custom_field_value issue_custom FORCE INDEX(issueIdIndex) ON issue.id = issue_custom.issue_id |
| | | WHERE 1=1 |
| | | AND issue.parent_issue_id IS NULL |
| | | <choose> |
| | | <when test="useValues.size != 0"> |
| | | AND issue_custom.use_value IN |
| | | <foreach collection="useValues" item="item" index="index" separator="," open="(" close=")"> |
| | | #{item} |
| | | </foreach> |
| | | </when> |
| | | </choose> |
| | | </select> |
| | | |
| | | </mapper> |
| | |
| | | $scope.fn.getDownTableConfigs = getDownTableConfigs; |
| | | $scope.fn.containsPartner = containsPartner; |
| | | $scope.fn.onActivate = onActivate; |
| | | $scope.fn.makePartnersEmail = makePartnersEmail; |
| | | |
| | | // 이슈 목록 컨트롤러 vm, fn 상속 중 |
| | | $scope.vm.viewer = {}; |
| | |
| | | |
| | | $scope.vm.form = { |
| | | issues : [], //연관 일감 |
| | | issuesDown : [] // 하위 일감 |
| | | issuesDown : [], // 하위 일감 |
| | | issueCompanyVos : [], |
| | | issueIspVos : [], |
| | | issueHostingVos : [] |
| | | }; |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | // 이슈명을 클릭하면 이슈 상세 정보를 조회한다. |
| | | $rootScope.$on("getIssueDetail", function (event, args) { |
| | | $scope.vm.viewer.id = args["id"]; |
| | | $scope.fn.getIssueDetail(); |
| | | }); |
| | | // $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(); |
| | | }); |
| | | // $scope.$on("getIssueDetail", function (event, args) { |
| | | // $scope.vm.viewer.id = args["id"]; |
| | | // $scope.fn.getIssueDetail(); |
| | | // }); |
| | | |
| | | $scope.$watch(function() { |
| | | return $rootScope.currentDetailIssueId; |
| | | }, function() { |
| | | if ($rootScope.currentDetailIssueId != null) { |
| | | $scope.vm.viewer.id = $rootScope.currentDetailIssueId; |
| | | $scope.fn.getIssueDetail(); |
| | | } |
| | | }, true); |
| | | |
| | | // 초기화 해야할 할목을 지정하여 다른 이슈를 클릭할 때 초기화해준다. |
| | | function initReload() { |
| | |
| | | $scope.vm.issueForm.issueStatusList = []; |
| | | $scope.vm.issueForm.issueStatusId = ""; |
| | | $scope.vm.issueTypeId = $rootScope.getCurrentIssueTypeId(); |
| | | /*if ($scope.$root.$$phase !== '$apply' && $scope.$root.$$phase !== '$digest') { |
| | | $scope.$apply(); |
| | | }*/ |
| | | // if ($scope.$root.$$phase !== '$apply' && $scope.$root.$$phase !== '$digest') { |
| | | // $scope.$apply(); |
| | | // } |
| | | } |
| | | |
| | | // 이슈 상태 변경 |
| | |
| | | $scope.fn.getDownTableConfigs(); |
| | | |
| | | Issue.detail($resourceProvider.getContent( |
| | | {id : $scope.vm.viewer.id, deep : "02", customFields : $scope.vm.customFields}, |
| | | {id : $scope.vm.viewer.id, deep : "02"}, |
| | | $resourceProvider.getPageContent(0, 1))).then(function (result) { |
| | | |
| | | if (result.data.message.status === "success") { |
| | |
| | | } |
| | | $scope.vm.viewer.issueRelationVos = result.data.data.issueRelationVos; |
| | | $scope.vm.viewer.issueDownVos = result.data.data.issueDownVos; |
| | | |
| | | if ($rootScope.workProject.id > -1) { |
| | | $rootScope.changeLastProject(result.data.data.projectVo.id); |
| | | } |
| | | } |
| | | } |
| | | else { |
| | |
| | | }); |
| | | } |
| | | |
| | | // 업체/ISP/호스팅 배열값을 하나로 합쳐서 메일 클릭시 전달 |
| | | function makePartnersEmail() { |
| | | $scope.vm.form.partnersEmail = $scope.vm.viewer.issueCompanyVos.concat($scope.vm.viewer.issueIspVos, $scope.vm.viewer.issueHostingVos) |
| | | return $scope.vm.form.partnersEmail; |
| | | } |
| | | |
| | | // 특정 사용자에게 이슈를 메일로 발송 |
| | | function sendMail(issueId, projectId) { |
| | | makePartnersEmail(); |
| | | $uibModal.open({ |
| | | templateUrl : 'views/issue/issueSendMail.html', |
| | | size : "md", |
| | |
| | | parameter : function () { |
| | | return { |
| | | departmentVos : [$scope.vm.form.issues[0].departmentVos], |
| | | issueCompanyFields : [$scope.vm.form.issues[0].issueCompanyVos], |
| | | issueIspFields : [$scope.vm.form.issues[0].issueIspVos], |
| | | issueHostingFields : [$scope.vm.form.issues[0].issueHostingVos], |
| | | partners : $scope.vm.form.partnersEmail, |
| | | issueId : issueId, |
| | | projectId : projectId |
| | | // issueCompanyFields : [$scope.vm.viewer.issueCompanyVos[0]], |
| | | // issueIspFields : [$scope.vm.viewer.issueIspVos[0]], |
| | | // issueHostingFields : [$scope.vm.viewer.issueHostingVos[0]], |
| | | }; |
| | | } |
| | | } |
| | |
| | | // 현재 상세화면으로 보려고하는 이슈 id를 기억한다. |
| | | $rootScope.currentDetailIssueId = id; |
| | | // 이슈 상세 화면 요청 |
| | | $rootScope.$broadcast("getIssueDetail", { |
| | | id : id |
| | | }); |
| | | // $scope.$broadcast("getIssueDetail", { |
| | | // id : id |
| | | // }); |
| | | } |
| | | |
| | | |
| | | // 목록 화면으로 변경한다. |
| | | function listView() { |
| | |
| | | $scope.vm.responseData.data = angular.copy(temp); |
| | | // 마지막으로 보고있던 이슈 id를 초기화한다. |
| | | $rootScope.currentDetailIssueId = null; |
| | | $scope.$broadcast("getIssueList", {id: $rootScope.currentDetailIssueId}); |
| | | } |
| | | |
| | | // 이슈 테이블 설정 |
| | |
| | | if (detail) { |
| | | changeDetailView(result.data.data[0].id); |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | SweetAlert.error($filter("translate")("issue.failedIssueLookup"), result.data.message.message); // 이슈 조회 실패 |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 이메일 프로젝트 경로로 이동 후 상세 진입시 조회 |
| | | function getDetailList(projectKey, number) { |
| | | var conditions = { |
| | | projectKey : projectKey, |
| | | combinationIssueNumber : number |
| | | }; |
| | | |
| | | Issue.find($resourceProvider.getContent(conditions, |
| | | $resourceProvider.getPageContent(0, 1))).then(function (result) { |
| | | |
| | | if (result.data.message.status === "success") { |
| | | if (result.data.data != null && result.data.data.length > 0) { |
| | | $scope.vm.projectKey = result.data.data[0].projectKey; |
| | | $scope.vm.issueNumber = result.data.data[0].issueNumber; |
| | | $scope.vm.responseData = result.data; |
| | | |
| | | changeDetailView(result.data.data[0].id); |
| | | } |
| | | } |
| | | else { |
| | |
| | | // 파라미터 읽기 |
| | | var params = $rootScope.previousGetParams; |
| | | if ($rootScope.isDefined(params)) { |
| | | $rootScope.$broadcast("makeIssueSearch", { projectKey : params.projectKey, issueNumber : params.issueNumber }); |
| | | // $rootScope.$broadcast("makeIssueSearch", { projectKey : params.projectKey, issueNumber : params.issueNumber }); |
| | | getDetailList(params.projectKey, params.issueNumber); |
| | | $rootScope.previousGetParams = null; |
| | | // $rootScope.issueTypeId = $rootScope.issueTypeMenu.id; |
| | | return; |
| | |
| | | removeManager : removeManager, // 전송 대상자 삭제 |
| | | cancel : cancel, // 팝업 창 닫기 |
| | | formSubmit : formSubmit, // 폼 전송 |
| | | formCheck : formCheck // 폼 체크 |
| | | // formCheck : formCheck // 폼 체크 |
| | | }; |
| | | |
| | | |
| | | $scope.vm = { |
| | | form : { |
| | | id : parameter.issueId, // 이슈 번호 |
| | | projects : [{ id : parameter.projectId}], // 프로젝트 |
| | | users : [] // 메일 전송받는 사용자 |
| | | partners : parameter.partners, |
| | | users : [], // 메일 전송받는 사용자 |
| | | issueCompanyVos : [], |
| | | issueIspVos : [], |
| | | issueHostingVos : [] |
| | | // companyFields : parameter.issueCompanyFields, // 업체 이메일 |
| | | // ispFields : parameter.issueIspFields, // ISP 이메일 |
| | | // hostingFields : parameter.issueHostingFields, // 호스팅 이메일 |
| | | }, |
| | | userName : "", |
| | | partnerName : "", |
| | | autoCompletePage : { |
| | | user : { |
| | | page : 0, |
| | | totalPage : 0 |
| | | }, |
| | | partnersMail : { |
| | | page : 0, |
| | | totalPage :0 |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | angular.extend(this, $controller('autoCompleteController', {$scope : $scope, $injector : $injector})); |
| | | |
| | | function formCheck(formInvalid) { |
| | | if (formInvalid) { |
| | | return true; |
| | | } |
| | | |
| | | if ($scope.vm.form.users.length < 1) { |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | // function formCheck(formInvalid) { |
| | | // if (formInvalid) { |
| | | // return true; |
| | | // } |
| | | // |
| | | // if ($scope.vm.form.users.length < 1) { |
| | | // return true; |
| | | // } |
| | | // |
| | | // return false; |
| | | // } |
| | | |
| | | // 폼 전송 |
| | | function formSubmit() { |
| | | $rootScope.spinner = true; |
| | | |
| | | var content = { |
| | | id : $scope.vm.form.id, |
| | | sendEmails : (function () { |
| | | var sendEmails = []; |
| | | |
| | | angular.forEach($scope.vm.form.users, function (user) { |
| | | sendEmails.push($rootScope.encryption(user.account)); |
| | | angular.forEach($scope.vm.form.projects, function (project) { |
| | | sendEmails.push(project.id); |
| | | }); |
| | | |
| | | return sendEmails; |
| | |
| | | }); |
| | | } |
| | | |
| | | // function formSubmit() { |
| | | // $rootScope.spinner = true; |
| | | // |
| | | // var content = { |
| | | // id : $scope.vm.form.id, |
| | | // companyFieldsEmail : $scope.vm.form.companyFieldsEmail, |
| | | // ispFieldsEmail : $scope.vm.form.ispFieldsEmail, |
| | | // hostingFieldsEmail : $scope.vm.form.hostingFieldsEmail, |
| | | // sendEmails : (function () { |
| | | // var sendEmails = []; |
| | | // |
| | | // angular.forEach($scope.vm.form.projects, function (project) { |
| | | // sendEmails.push(project.id); |
| | | // }); |
| | | // |
| | | // return sendEmails; |
| | | // })() |
| | | // }; |
| | | // |
| | | // Issue.findMailTargetAll($resourceProvider.getContent( |
| | | // content, |
| | | // $resourceProvider.getPageContent(0, 10))).then(function (result) { |
| | | // |
| | | // if (result.data.message.status === "success") { |
| | | // SweetAlert.success($filter("translate")("issue.succeededIssueMail"), $filter("translate")("issue.sentToTheSelectedUser")); // "이슈 메일 발송 완료" |
| | | // $scope.fn.cancel(); |
| | | // } |
| | | // else { |
| | | // SweetAlert.error($filter("translate")("issue.failedIssueMail"), result.data.message.message); // "이슈 메일 발송 실패" |
| | | // } |
| | | // |
| | | // $rootScope.spinner = false; |
| | | // }); |
| | | // } |
| | | |
| | | |
| | | // 사용자 auto complete callback function |
| | | function getUserListCallBack(result) { |
| | | $scope.vm.autoCompletePage.user.totalPage = result.data.page.totalPage; |
| | |
| | | return response; |
| | | }); |
| | | }, |
| | | findMailTargetAll : function (conditions) { |
| | | return $http.post("issue/findMailTargetAll", conditions).then(function (response) { |
| | | $log.debug("이슈 이메일 발송 결과 : ", response); |
| | | return response; |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | ]) |
| | |
| | | $scope.fn.getPartnerList = getPartnerList; // 업체/isp/호스팅 목록 조회 |
| | | $scope.fn.getIssueTypeList = getIssueTypeList; // 이슈 유형 목록 조회 |
| | | $scope.fn.getCustomFieldList = getCustomFieldList; // 사용자 정의 필드 목록 조회 |
| | | $scope.fn.getMailTargetAll = getMailTargetAll; // 사용자 정의 필드 목록 조회 |
| | | |
| | | function getUserList(query, excludeList, page, callBack) { |
| | | var conditions = { |
| | |
| | | |
| | | return deferred.promise; |
| | | } |
| | | |
| | | function getMailTargetAll(query, excludeList, page, callBack) { |
| | | var conditions = { |
| | | id : query, |
| | | excludeIds : (function () { |
| | | var excludeIds = []; |
| | | |
| | | angular.forEach(excludeList, function (exclude) { |
| | | excludeIds.push(exclude.id); |
| | | }); |
| | | |
| | | return excludeIds; |
| | | })(), |
| | | partnersEmailIds : (function () { |
| | | var partnersEmailIds = []; |
| | | |
| | | angular.forEach($scope.vm.form.partners, function (partner) { |
| | | partnersEmailIds.push(partner.email); |
| | | }); |
| | | |
| | | return partnersEmailIds; |
| | | })(), |
| | | }; |
| | | var deferred = $q.defer(); |
| | | |
| | | Issue.findMailTargetAll($resourceProvider.getContent( // 페이징 업데이트가 필요한 컴포넌트 일경우, page 업데이트가 있을 경우 기본 10개씩 가져오고 아닐경우 25개씩 가져온다. |
| | | conditions, $resourceProvider.getPageContent($rootScope.isDefined(page) ? page : 0, $rootScope.isDefined(page) ? 10 : 25))).then(function (result) { |
| | | if (result.data.message.status === "success") { |
| | | |
| | | if ($rootScope.isDefined(callBack)) { |
| | | callBack(result); |
| | | } |
| | | |
| | | deferred.resolve(result.data.data); |
| | | } |
| | | else { |
| | | SweetAlert.swal($filter("translate")("issue.failedToIssueTypeListLookup"), result.data.message.message, "error"); // "이슈 유형 목록 조회 실패" |
| | | } |
| | | }); |
| | | |
| | | return deferred.promise; |
| | | } |
| | | } |
| | | ]); |
| | | } |
| | |
| | | |
| | | // 이미지 갤러리 만들기 |
| | | function makeNgImageGallery() { |
| | | var makeTag = '<ng-image-gallery images="images" thumb-size="80" bubbles="true" bubble-size="50" img-bubbles="true"></ng-image-gallery>'; |
| | | var makeTag = '<ng-image-gallery images="images" thumb-size="60" bubbles="true" bubble-size="50" img-bubbles="true"></ng-image-gallery>'; |
| | | var linkFn = $compile(makeTag); |
| | | var content = linkFn($scope); |
| | | $element.append(content); |
| | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | makeTag += "<span ng-click='fn.remove(" + key.fieldKey + ")'>×</span>"; |
| | | makeTag += "</p>"; |
| | | if (target.fieldValue !== null) { |
| | | makeTag += "<span></span>"; |
| | | makeTag += "</p>"; |
| | | } |
| | | else { |
| | | makeTag += "<span ng-click='fn.remove(" + key.fieldKey + ")'>×</span>"; |
| | | makeTag += "</p>"; |
| | | } |
| | | }); |
| | | |
| | | var linkFn = $compile(makeTag); |
| | |
| | | }; |
| | | |
| | | $rootScope.changeLastProject = function (projectId, reload = true) { |
| | | if (User != null) { |
| | | User.updateLastProject($resourceProvider.getContent( |
| | | {lastProjectId: projectId}, |
| | | $resourceProvider.getPageContent(0, 0))).then(function (result) { |
| | | if ($rootScope.workProject == null || $rootScope.workProject.id !== projectId ) { |
| | | if (User != null) { |
| | | User.updateLastProject($resourceProvider.getContent( |
| | | {lastProjectId: projectId}, |
| | | $resourceProvider.getPageContent(0, 0))).then(function (result) { |
| | | |
| | | if (result.data.message.status === "success") { |
| | | $rootScope.user = result.data.data; |
| | | $rootScope.projects.forEach(function (el) { |
| | | if (el.id == projectId) { |
| | | $rootScope.workProject = el; |
| | | if (result.data.message.status === "success") { |
| | | $rootScope.user = result.data.data; |
| | | $rootScope.projects.forEach(function (el) { |
| | | if (el.id == projectId) { |
| | | $rootScope.workProject = el; |
| | | |
| | | $rootScope.$broadcast("changeLastProject", { id : el.id }); |
| | | } |
| | | }); |
| | | $state.go($state.current, {}, {reload: reload}); |
| | | } |
| | | }); |
| | | $rootScope.$broadcast("changeLastProject", {id: el.id}); |
| | | } |
| | | }); |
| | | $state.go($state.current, {}, {reload: reload}); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | |
| | | <span class="issue-detail-label" style="position: relative; top: 1rem" ng-show="vm.viewer.issueCustomFields == ''">사용자 정의 필드값이 없습니다.</span> |
| | | </div> |
| | | </div> |
| | | <div class="col-md-2"> |
| | | <issue-detail-image-preview images="vm.images"></issue-detail-image-preview> |
| | | </div> |
| | | <div ng-show="vm.images.length < 1" class="detail-not-elements width-100"> |
| | | </div> |
| | | </div> |
| | | <!-- 사용자 정의 필드 --> |
| | | <div class="row"> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="pdt0" style="position: relative; bottom: 1rem"> |
| | | <issue-detail-image-preview images="vm.images"></issue-detail-image-preview> |
| | | </div> |
| | | <div ng-show="vm.images.length < 1" class="detail-not-elements width-100"> |
| | | <span></span> |
| | | </div> |
| | | |
| | | </div> |
| | | |
| | | |
| | | <!-- <div class=""> |
| | | <label class="issue-detail-label"><span>{{vm.viewer.issueCustomFieldValueVos[0].useValue}}</span> </label> |
| | |
| | | <div class="form-group"> |
| | | <div class=""> |
| | | <span translate="companyField.email">이메일</span>: |
| | | <span class="email_color">{{vm.viewer.issueCompanyVos[0].email}}</span> |
| | | <span class="email_color cursor" ng-click="fn.sendMail(vm.viewer.id, vm.viewer.projectVo.id)">{{vm.viewer.issueCompanyVos[0].email}}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="form-group"> |
| | | <div class=""> |
| | | <span translate="ispField.email">이메일</span>: |
| | | <span class="email_color">{{vm.viewer.issueIspVos[0].email}}</span> |
| | | <span class="email_color cursor" ng-click="fn.sendMail(vm.viewer.id, vm.viewer.projectVo.id)">{{vm.viewer.issueIspVos[0].email}}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <div class="form-group"> |
| | | <div class=""> |
| | | <span translate="hostingField.email">이메일</span>: |
| | | <span class="email_color">{{vm.viewer.issueHostingVos[0].email}}</span> |
| | | <span class="email_color cursor" ng-click="fn.sendMail(vm.viewer.id, vm.viewer.projectVo.id)">{{vm.viewer.issueHostingVos[0].email}}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | <!-- 프로젝트 --> |
| | | <issue-search-array-view-element lists="vm.projects" |
| | | type="'project'"></issue-search-array-view-element> |
| | | <p ng-if="$root.isDefined(vm.projectKey)"> |
| | | {{vm.projectKey}} |
| | | </p> |
| | | |
| | | <!-- 이슈 타입 --> |
| | | <issue-search-field-key-view-element lists="vm.issueTypes" |
| | | keys="vm.search.issueTypeIds"></issue-search-field-key-view-element> |
| | |
| | | <!-- 이슈 상태 --> |
| | | <issue-search-field-key-view-element lists="vm.issueStatuses" |
| | | keys="vm.search.issueStatusIds"></issue-search-field-key-view-element> |
| | | |
| | | <!-- 이슈 번호 --> |
| | | <p ng-if="$root.isDefined(vm.issueNumber)"> |
| | | {{vm.issueNumber}} |
| | | </p> |
| | | |
| | | <p ng-if="$root.isDefined(vm.search.combinationIssueNumber)"> |
| | | {{vm.search.combinationIssueNumber}} |
| | | <span ng-click="vm.search.combinationIssueNumber = ''">×</span> |
| | | </p> |
| | | |
| | | <!-- 이슈 내용 --> |
| | | <p ng-if="$root.isDefined(vm.search.description)"> |
| | |
| | | options="::vm.issueStatuses"></ng-dropdown-multiselect> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="row"> |
| | | <div class="col-lg-3"> |
| | | <div class="form-group"> |
| | | <label> <span translate="issue.issueNumber">이슈 번호</span></label> |
| | |
| | | autocomplete="off" |
| | | kr-input |
| | | maxlength="20" |
| | | ng-model="vm.issueNumber"> |
| | | <!-- ng-model="vm.search.combinationIssueNumber">--> |
| | | ng-model="vm.search.combinationIssueNumber"> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="row"> |
| | | <div class="col-lg-3"> |
| | | <div class="form-group"> |
| | | <label> <span translate="issue.issueContent">이슈 내용</span></label> |
| | |
| | | data-input-name="severities" |
| | | selected-model="vm.search.severityIds" |
| | | options="::vm.severities"></ng-dropdown-multiselect> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="col-lg-3"> |
| | | <div class="form-group"> |
| | | <label> <span translate="common.assigneeTeam">담당부서</span></label> |
| | | <js-autocomplete-multi data-input-name="departments" |
| | | selected-model="vm.departments" |
| | | search="vm.departmentName" |
| | | input-disabled="false" |
| | | source="fn.getUserDepartmentList(vm.departmentName, vm.departments)" |
| | | translation-texts="{ count : 'common.userNum', empty : 'common.emptyProjectDepartment' }" |
| | | extra-settings="{ displayProp : 'byName' , idProp : 'id', widthable : false, width : '', imageable : true, imagePathProp : 'profile', type : 'department', maxlength : 100 }"> |
| | | </js-autocomplete-multi> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="col-lg-3"> |
| | | <div class="form-group"> |
| | | <label> <span translate="common.assigneeTeam">담당부서</span></label> |
| | | <js-autocomplete-multi data-input-name="departments" |
| | | selected-model="vm.departments" |
| | | search="vm.departmentName" |
| | | input-disabled="false" |
| | | source="fn.getUserDepartmentList(vm.departmentName, vm.departments)" |
| | | translation-texts="{ count : 'common.userNum', empty : 'common.emptyProjectDepartment' }" |
| | | extra-settings="{ displayProp : 'byName' , idProp : 'id', widthable : false, width : '', imageable : true, imagePathProp : 'profile', type : 'department', maxlength : 100 }"> |
| | | </js-autocomplete-multi> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="col-lg-3" ng-repeat="customField in vm.customFields"> |
| | | <label>{{::customField.name}}</label> |
| | | |
| | |
| | | ng-click="fn.removeManager($index)">×</span> |
| | | </span> |
| | | </div> |
| | | <js-input-autocomplete data-input-name="users" |
| | | owl-auto-focus |
| | | target=".auto-complete-input" |
| | | selected-model="vm.form.users" |
| | | search="vm.userName" |
| | | page="vm.autoCompletePage.user.page" |
| | | total-page="vm.autoCompletePage.user.totalPage" |
| | | source="fn.getUserList(vm.userName, vm.form.users, vm.autoCompletePage.user.page, fn.getUserListCallBack)" |
| | | translation-texts="{ empty : 'common.emptyUser'}" |
| | | input-disabled="vm.form.projects.length == 0" |
| | | extra-settings="{ displayProp : 'byName' , idProp : 'id', imageable : true, imagePathProp : 'profile', |
| | | type : 'user', maxlength : 100, autoResize : true, stopRemoveBodyEvent : true }"></js-input-autocomplete> |
| | | |
| | | <!-- <js-autocomplete-single data-input-name="issue"--> |
| | | <!-- selected-model="vm.form.issues"--> |
| | | <!-- search="vm.issueName"--> |
| | | <!-- source="fn.getIssueList(vm.issueName, vm.issueTypeId, vm.form.issues, vm.autoCompletePage.issue.page, fn.getIssueListCallBack)"--> |
| | | <!-- page="vm.autoCompletePage.issue.page"--> |
| | | <!-- total-page="vm.autoCompletePage.issue.totalPage"--> |
| | | <!-- input-disabled="false"--> |
| | | <!-- translation-texts="{ empty : 'common.emptyIssue' }"--> |
| | | <!-- extra-settings="{ displayProp : 'title' , idProp : 'id', imageable : false, imagePathProp : '',--> |
| | | <!-- type : '', maxlength : 200, autoResize : true, stopRemoveBodyEvent : true }"></js-autocomplete-single>--> |
| | | |
| | | <!-- {{vm.form.companyFieldsEmail}}--> |
| | | <label><span>협력사 메일</span></label> |
| | | <js-autocomplete-multi data-input-name="partnersEmail" |
| | | selected-model="vm.form.partnersEmail" |
| | | search="vm.partnerName" |
| | | source="fn.getMailTargetAll(vm.form.partnersEmail)" |
| | | input-disabled="false" |
| | | page="vm.autoCompletePage.partnersMail.page" |
| | | total-page="vm.autoCompletePage.partnersMail.totalPage" |
| | | modal-form-auto-scroll |
| | | extra-settings="{ displayProp : 'byName' , idProp : 'email', imageable : false, maxlength : 100, autoResize : true }"></js-autocomplete-multi> |
| | | |
| | | <!-- <ng-dropdown-multiselect class="multiSelect cursor"--> |
| | | <!-- data-input-name="companyFieldsEmail"--> |
| | | <!-- selected-model="vm.form.companyFieldsEmail.concat(vm.form.ispFieldsEmail,vm.form.hostingFieldsEmail)"--> |
| | | <!-- extra-settings="{ stringTypeOption : true }"--> |
| | | <!-- options="vm.options.companyFieldsEmail"></ng-dropdown-multiselect>--> |
| | | |
| | | <!-- <span class="issue-detail-label" translate="companyField.info"></span>--> |
| | | <!-- <input ng-if="vm.form.companyFieldsEmail != null"--> |
| | | <!-- type="text"--> |
| | | <!-- class="form-control"--> |
| | | <!-- kr-input--> |
| | | <!-- autocomplete="off"--> |
| | | <!-- ng-model="vm.form.companyFieldsEmail">--> |
| | | |
| | | <!-- <span class="issue-detail-label" translate="ispField.info"></span>--> |
| | | <!-- <input ng-if="vm.form.ispFieldsEmail != null"--> |
| | | <!-- type="text"--> |
| | | <!-- class="form-control"--> |
| | | <!-- kr-input--> |
| | | <!-- autocomplete="off"--> |
| | | <!-- ng-model="vm.form.ispFieldsEmail">--> |
| | | |
| | | <!-- <span class="issue-detail-label" translate="hostingField.info"></span>--> |
| | | <!-- <input ng-if="vm.form.hostingFieldsEmail != null"--> |
| | | <!-- type="text"--> |
| | | <!-- class="form-control"--> |
| | | <!-- kr-input--> |
| | | <!-- autocomplete="off"--> |
| | | <!-- ng-model="vm.form.hostingFieldsEmail">--> |
| | | |
| | | <!-- <a style="display: flex; text-align: center; justify-content: center;">--> |
| | | <!-- <i class="os-icon os-icon-email-forward mr-20 mt-20 cursor" ng-click="fn.formSubmit(data.id)">1</i>--> |
| | | <!-- <i class="os-icon os-icon-email-forward mr-20 mt-20 cursor" ng-click="fn.formSubmit(data.id)">2</i>--> |
| | | <!-- <i class="os-icon os-icon-email-forward mr-20 mt-20 cursor" ng-click="fn.formSubmit(data.id)">3</i>--> |
| | | <!-- </a>--> |
| | | <!-- <div class="modal-content">--> |
| | | <!-- <a style="display: flex; text-align: center; justify-content: center;">--> |
| | | <!-- <img onclick="emailTemplate()" id="template1" class="cursor" src="assets/images/btn_facebook.png">--> |
| | | <!-- <img onclick="emailTemplate()" id="template2" class="cursor" src="assets/images/btn_kakao.png">--> |
| | | <!-- <img onclick="emailTemplate()" id="template3" class="cursor" src="assets/images/btn_google.png">--> |
| | | <!-- </a>--> |
| | | <!-- </div>--> |
| | | <!-- <form action="${pageContext.request.contextPath}/updatetNoticePro.do" method="post" enctype="multipart/form-data" name="noticeForm">--> |
| | | <!-- <input type='file' id="filename" name="filename"/>--> |
| | | <!-- <img id="preImage" src="${pageContext.request.contextPath}/saveFile/${noticeVO.filename}" alt="image_title" onerror='this.src="${pageContext.request.contextPath}/images/no_img.jpg"'/>--> |
| | | <!-- </form>--> |
| | | |
| | | </div> |
| | | </form> |
| | | |
| | | </div> |
| | | <!-- <h6>{{vm.form.companyFieldsEmail}}</h6>--> |
| | | <!-- <span>{{vm.form.id}}===============</span>--> |
| | | <!-- <h6>{{vm.form.ispFieldsEmail}}===============</h6>--> |
| | | <!-- <span>===============</span>--> |
| | | <!-- <h6>{{vm.form.hostingFieldsEmail}}</h6>--> |
| | | <!-- <div style="display: flex; text-align: center">--> |
| | | <!-- 템플릿1--> |
| | | <!-- </div>--> |
| | | <!-- <div style="border: 1px #111111; margin-left: 20px; box-sizing: border-box;">--> |
| | | <!-- 템플릿2--> |
| | | <!-- <div style="border: 1px #111111; margin-left: 20px; box-sizing: border-box;">--> |
| | | <!-- </div>--> |
| | | <!-- <div style="border: 1px #111111; margin-left: 20px; box-sizing: border-box;">--> |
| | | <!-- 템플릿3--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | |
| | | <div class="modal-footer buttons-on-right"> |
| | | <button type="button" class="btn btn-md btn-grey" ng-click="fn.cancel()"><span |
| | |
| | | </button> |
| | | </div> |
| | | </div> |
| | | |
| | | <script> |
| | | |
| | | function emailTemplate() { |
| | | $('#template1').click(function() { |
| | | $('#template1').hide(); |
| | | }); |
| | | |
| | | $('#template2').click(function() { |
| | | $('#template2').hide(); |
| | | }); |
| | | |
| | | $('#template3').click(function() { |
| | | $('#template3').hide(); |
| | | }); |
| | | } |
| | | |
| | | function changeIMG() { |
| | | $('#template1').attr("src", "assets/images/previewTemplate.png") |
| | | } |
| | | </script> |