package kr.wisestone.owl.service.impl; import com.google.common.collect.Lists; import kr.wisestone.owl.constant.MsgConstants; import kr.wisestone.owl.domain.*; import kr.wisestone.owl.domain.enumType.EmailType; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.repository.UserInviteRepository; import kr.wisestone.owl.service.*; import kr.wisestone.owl.util.CommonUtil; import kr.wisestone.owl.web.form.UserInviteForm; import org.apache.commons.validator.routines.EmailValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.HashMap; import java.util.List; import java.util.Map; @Service public class UserInviteServiceImpl extends AbstractServiceImpl> implements UserInviteService { private static final Logger log = LoggerFactory.getLogger(UserInviteServiceImpl.class); @Autowired private UserInviteRepository userInviteRepository; @Autowired private UserInviteProjectService userInviteProjectService; @Autowired private SystemEmailService systemEmailService; @Autowired private ProjectRoleService projectRoleService; @Autowired private ProjectRoleUserService projectRoleUserService; @Autowired private UserWorkspaceService userWorkspaceService; @Autowired private ProjectService projectService; @Autowired private UserService userService; @Autowired private WorkspaceService workspaceService; @Autowired private SimpMessagingTemplate simpMessagingTemplate; @Override protected JpaRepository getRepository() { return this.userInviteRepository; } // 해당 업무 공간에 참여하고 있는지 확인 후 업무 공간에 참여시킨다. 또한 프로젝트에 참여되어 있는지 확인 후 프로젝트에도 참여시킨다. @Override @Transactional public void checkInviteUser(User user) { List userInvites = this.userInviteRepository.findByEmailAndStatus(user.getAccount(), UserInvite.WORKSPACE_JOIN_READY); for (UserInvite userInvite : userInvites) { Workspace workspace = userInvite.getWorkspace(); // 업무 공간 참여 this.includeWorkspace(user, workspace); // 프로젝트에 참여 this.includeProject(user, userInvite); // 업무 공간 초대 상태를 완료로 업데이트 userInvite.setStatus(UserInvite.WORKSPACE_JOIN_COMPLETE); } if (userInvites.size() > 0) { // 프로젝트 역할과 사용자 연결 업데이트 //this.userService.saveAndFlush(user); // 초대 상태 업데이트 this.userInviteRepository.saveAll(userInvites); } } // 업무 공간에 참여 private void includeWorkspace(User user, Workspace workspace) { UserWorkspace userWorkspace = this.userWorkspaceService.findByUserIdAndWorkspaceId(user.getId(), workspace.getId()); if (userWorkspace != null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.INVITE_USER_USED_WORKSPACE)); } // 해당 업무 공간의 활성인 사용자 Integer activeUserCount = this.userWorkspaceService.countByWorkspaceIdAndUseYn(workspace.getId(), true); // 업무 공간에 더이상 사용자를 받을 공간이 없으면 비활성 상태로 업무 공간와 사용자를 연결한다. if (workspace.getMaxUser() > activeUserCount) { this.userWorkspaceService.addUserWorkspace(user, workspace, false, true); } else { this.userWorkspaceService.addUserWorkspace(user, workspace, false, false); // 웹 소켓으로 업무 공간 관리자에게 인원수 초과를 알려준다. List userWorkspaces = this.userWorkspaceService.findByWorkspaceIdAndManagerYn(workspace.getId(), true); // 관리자에게 알림 팝업 표시 && 메일 전송 for (UserWorkspace managerUserWorkspace : userWorkspaces) { User sendUser = managerUserWorkspace.getUser(); this.simpMessagingTemplate.convertAndSendToUser(sendUser.getAccount(), "/notification/workspace-max-user-excess", this.messageAccessor.getMessage(MsgConstants.WORKSPACE_MAX_USER_EXCESS)); Map workspaceMap = new HashMap<>(); workspaceMap.put("workspaceName", workspace.getName()); workspaceMap.put("activeUser", activeUserCount); workspaceMap.put("disableUser", this.userWorkspaceService.countByWorkspaceIdAndUseYn(workspace.getId(), false)); // 업무 공간 활성 사용자 초과 알림 메일 전송 this.systemEmailService.directEmail(new String[]{sendUser.getAccount()}, EmailType.WORKSPACE_MAX_USER_EXCESS, workspaceMap, null); } } } // 기본 업무 공간에 참여 public void includePrimaryWorkspace(User user, Workspace workspace) { // 해당 업무 공간의 활성인 사용자 Integer activeUserCount = this.userWorkspaceService.countByWorkspaceIdAndUseYn(workspace.getId(), true); // 업무 공간에 더이상 사용자를 받을 공간이 없으면 비활성 상태로 업무 공간와 사용자를 연결한다. if (workspace.getMaxUser() > activeUserCount) { this.userWorkspaceService.addUserWorkspace(user, workspace, false, true); } else { this.userWorkspaceService.addUserWorkspace(user, workspace, false, false); // 웹 소켓으로 업무 공간 관리자에게 인원수 초과를 알려준다. List userWorkspaces = this.userWorkspaceService.findByWorkspaceIdAndManagerYn(workspace.getId(), true); // 관리자에게 알림 팝업 표시 && 메일 전송 for (UserWorkspace managerUserWorkspace : userWorkspaces) { User sendUser = managerUserWorkspace.getUser(); this.simpMessagingTemplate.convertAndSendToUser(sendUser.getAccount(), "/notification/workspace-max-user-excess", this.messageAccessor.getMessage(MsgConstants.WORKSPACE_MAX_USER_EXCESS)); Map workspaceMap = new HashMap<>(); workspaceMap.put("workspaceName", workspace.getName()); workspaceMap.put("activeUser", activeUserCount); workspaceMap.put("disableUser", this.userWorkspaceService.countByWorkspaceIdAndUseYn(workspace.getId(), false)); // 업무 공간 활성 사용자 초과 알림 메일 전송 this.systemEmailService.directEmail(new String[]{sendUser.getAccount()}, EmailType.WORKSPACE_MAX_USER_EXCESS, workspaceMap, null); } } } // 프로젝트에 참여 private void includeProject(User user, UserInvite userInvite) { for (UserInviteProject userInviteProject : userInvite.getUserInviteProjects()) { Project project = userInviteProject.getProject(); // 기본 역할 확인 ProjectRole defaultProjectRole = this.projectRoleService.findByProjectIdAndRoleType(project.getId(), ProjectRole.TYPE_DEFAULT); // 관리자 역할 확인 ProjectRole managerProjectRole = this.projectRoleService.findByProjectIdAndRoleType(project.getId(), ProjectRole.TYPE_MANAGER); // 프로젝트 관리자 역할에 이미 연결되어 있으면 해당 프로젝트에 못들어간다. ProjectRoleUser managerProjectRoleUser = this.projectRoleUserService.findByProjectRoleIdAndUserId(managerProjectRole.getId(), user.getId()); if (managerProjectRoleUser != null) { continue; } ProjectRoleUser defaultProjectRoleUser = this.projectRoleUserService.findByProjectRoleIdAndUserId(defaultProjectRole.getId(), user.getId()); // 해당 역할에 사용자 연결이 안되어 있을 경우에만 연결 if (defaultProjectRoleUser == null) { user.addProjectRole(defaultProjectRole); } } } // 업무 공간에 초대한 정보를 저장하고 이미 가입되어 있는 사용자는 즉시 해당 업무 공간, 프로젝트에 참여시킨다. @Override @Transactional public void inviteWorkspace(UserInviteForm userInviteForm) { for (String email : userInviteForm.getEmails()) { // 이메일 유효성 검증 this.verifyEmail(CommonUtil.decryptAES128(email)); User user = this.userService.findByAccount(email); Workspace workspace = this.workspaceService.getWorkspace(this.userService.getUser(this.webAppUtil.getLoginId()).getLastWorkspaceId()); // 사용자가 이미 존재할 경우 해당 업무 공간에 초대한다. // 사용자가 없을 경우 초대 메일을 전달한다. // 초대받은 사용자는 회원 가입시 확인을 거쳐 해당 업무 공간로 가입시킨다. if (user != null) { // 이 초대를 보낸 사용자는 마지막으로 선택한 업무 공간에서 초대를 보낸 것이다. - 관리자뿐만 아니라 해당 업무 공간의 모든 사용자는 사람들을 초대할 수 있다. UserWorkspace userWorkspace = this.userWorkspaceService.findByUserIdAndWorkspaceId(user.getId(), workspace.getId()); if (userWorkspace != null) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.INVITE_USER_USED_WORKSPACE)); } else { // 업무 공간 기존 사용자에게 초대 메일 발송 - 자동으로 해당 업무 공간에 참여됨 this.addInvite(userInviteForm, workspace, email, EmailType.WORKSPACE_INVITE_SYSTEM_USER); // 해당 업무 공간에 가입 this.checkInviteUser(user); } } else { // 업무 공간 초대 메일 발송 - 사용자가 직접 가입해야함. this.addInvite(userInviteForm, workspace, email, EmailType.WORKSPACE_INVITE_NEW_USER); } } } // 이메일 유효성 검증 private void verifyEmail(String email) { if (StringUtils.isEmpty(email)) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.USER_INVALID_EMAIL)); } else { if (!EmailValidator.getInstance().isValid(email)) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.USER_INVALID_EMAIL)); } } } // 초대 정보 저장 및 메일 발송 private void addInvite(UserInviteForm userInviteForm, Workspace workspace, String email, EmailType emailType) { // user invite 정보를 생성. // 참여되는 프로젝트 셋팅 // 생성 종료 및 이메일 발송 UserInvite userInvite = this.userInviteRepository.findByEmailAndWorkspaceId(email, workspace.getId()); // 이미 초대장을 보낸적이 있으면 추가해야 할 프로젝트 정보를 추출한다. if (userInvite != null) { for (UserInviteProject userInviteProject : userInvite.getUserInviteProjects()) { Project project = userInviteProject.getProject(); for (int count = 0; count < userInviteForm.getProjectIds().size(); count++) { if (userInviteForm.getProjectIds().get(count).equals(project.getId())) { userInviteForm.getProjectIds().remove(count); break; } } } } else { List addProjectIds = this.checkHasProjectRole(email, userInviteForm.getProjectIds()); userInvite = new UserInvite(); userInvite.setEmail(email); userInvite.setStatus(UserInvite.WORKSPACE_JOIN_READY); userInvite.setWorkspace(workspace); // 만약 추가해야할 프로젝트가 없을 경우(이미 해당 프로젝트에 소속되어있을 경우) 여기서 중단한다. if (addProjectIds.isEmpty()) { this.userInviteRepository.saveAndFlush(userInvite); // 초대 메일을 발송한다. this.sendInviteEmail(workspace, emailType, email); return; } } this.userInviteRepository.saveAndFlush(userInvite); // 참여 프로젝트 셋팅 List userInviteProjects = this.userInviteProjectService.addUserInviteProject(userInviteForm.getProjectIds(), userInvite); if (!userInviteProjects.isEmpty()) { for (UserInviteProject userInviteProject : userInviteProjects) { userInvite.addUserInviteProjects(userInviteProject); } this.userInviteRepository.saveAndFlush(userInvite); } // 초대 메일을 발송한다. this.sendInviteEmail(workspace, emailType, email); } // 초대 메일을 발송한다. private void sendInviteEmail(Workspace workspace, EmailType emailType, String sendEmail) { Map userInviteMap = new HashMap<>(); userInviteMap.put("inviteUserName", this.webAppUtil.getLoginUser().getName()); userInviteMap.put("workspaceName", workspace.getName()); // 업무 공간 초대 메일 발송 this.systemEmailService.directEmail(new String[]{sendEmail}, emailType, userInviteMap, this.webAppUtil.getLoginUser().getAccount()); } // 해당 프로젝트역할에 사용자가 이미 소속되어 있는지 확인한다. private List checkHasProjectRole(String email, List projectIds) { List addProjectIds = Lists.newArrayList(); boolean projectHasRole = false; User user = this.userService.findByAccount(email); // 가입되어있지 않은 사용자는 체크하지 않는다. if (user == null) { return projectIds; } for (Long projectId : projectIds) { Project project = this.projectService.getProject(projectId); if (project != null) { // 프로젝트 참여 여부 확인 for (ProjectRole projectRole : project.getProjectRoles()) { ProjectRoleUser projectRoleUser = this.projectRoleUserService.findByProjectRoleIdAndUserId(projectRole.getId(), user.getId()); if (projectRoleUser != null) { projectHasRole = true; break; } } // 만약 프로젝트 역할에 소속되어 있지 않으면 초대를 하자. if (!projectHasRole) { addProjectIds.add(project.getId()); } } } return addProjectIds; } // 이전에 보낸 초대 정보 삭제 @Override @Transactional public void deleteUserInvite(Long workspaceId, List email) { List userInvites = this.userInviteRepository.findByWorkspaceIdAndEmailIn(workspaceId, email); this.userInviteRepository.deleteAll(userInvites); this.userInviteRepository.flush(); } }