-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
사용자 가입 요청 시 알람, 사용자 가입 승인 시 알람, 사용자 가입 거절 시 알람
- Loading branch information
Showing
4 changed files
with
199 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
..._WEB_SERVER/src/main/java/com/ucd/keynote/domain/notification/NotificationController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.ucd.keynote.domain.notification; | ||
|
||
import org.springframework.http.MediaType; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||
|
||
import java.io.IOException; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
|
||
@RestController | ||
public class NotificationController { | ||
// SSE 연결된 사용자들을 관리하기 위한 리스트 | ||
private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>(); | ||
|
||
// 클라이언트가 이 API를 호출하면 SSE 연결이 수립됨 | ||
@GetMapping(value = "/api/notifications/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | ||
public SseEmitter subscribe() { | ||
SseEmitter emitter = new SseEmitter(60 * 60 * 1000L); // 1시간 동안 연결 유지 | ||
emitters.add(emitter); | ||
|
||
emitter.onCompletion(() -> emitters.remove(emitter)); // 연결이 완료되면 삭제 | ||
emitter.onTimeout(() -> emitters.remove(emitter)); // 타임아웃 시 삭제 | ||
emitter.onError(e -> emitters.remove(emitter)); // 에러 발생 시 삭제 | ||
|
||
return emitter; | ||
} | ||
|
||
// 알림을 보낼 메소드 | ||
public void sendNotification(String message) { | ||
for (SseEmitter emitter : emitters) { | ||
try { | ||
emitter.send(SseEmitter.event().name("notification").data(message)); | ||
} catch (IOException e) { | ||
emitters.remove(emitter); // 실패한 emitter는 제거 | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
297 changes: 156 additions & 141 deletions
297
...ER/src/main/java/com/ucd/keynote/domain/organization/service/OrganizationJoinService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,155 +1,170 @@ | ||
package com.ucd.keynote.domain.organization.service; | ||
|
||
import com.ucd.keynote.common.service.AuthService; | ||
import com.ucd.keynote.domain.organization.dto.join.JoinRequestDTO; | ||
import com.ucd.keynote.domain.organization.dto.join.JoinRequestResponseDTO; | ||
import com.ucd.keynote.domain.organization.dto.join.JoinResponseDTO; | ||
import com.ucd.keynote.domain.organization.entity.Organization; | ||
import com.ucd.keynote.domain.organization.entity.UserOrganization; | ||
import com.ucd.keynote.domain.organization.entity.UserOrganizationId; | ||
import com.ucd.keynote.domain.organization.entity.join.OrganizationJoinRequest; | ||
import com.ucd.keynote.domain.organization.repository.OrganizationRepository; | ||
import com.ucd.keynote.domain.organization.repository.UserOrganizationRepository; | ||
import com.ucd.keynote.domain.organization.repository.join.OrganizationJoinRepository; | ||
import com.ucd.keynote.domain.user.entity.UserEntity; | ||
import lombok.AllArgsConstructor; | ||
import org.springframework.security.access.AccessDeniedException; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
@Service | ||
@AllArgsConstructor | ||
public class OrganizationJoinService { | ||
private final OrganizationJoinRepository organizationJoinRepository; | ||
private final OrganizationRepository organizationRepository; | ||
private final AuthService authService; | ||
private final UserOrganizationRepository userOrganizationRepository; | ||
|
||
// 가입 신청 처리 | ||
public JoinResponseDTO requestJoinOrganization(Long organizationId, JoinRequestDTO reqeust){ | ||
Organization organization = organizationRepository.findById(organizationId) | ||
.orElseThrow(() -> new IllegalArgumentException("조직이 존재하지 않습니다.")); | ||
UserEntity user = authService.getAuthenticatedUser(); | ||
|
||
// 사용자가 이미 조직에 속해 있는지 확인 | ||
boolean alreadyInOrganization = userOrganizationRepository.existsByOrganization_OrganizationIdAndUser_UserId(organizationId, user.getUserId()); | ||
if (alreadyInOrganization) { | ||
throw new IllegalStateException("사용자가 이미 조직에 속해 있습니다."); | ||
package com.ucd.keynote.domain.organization.service; | ||
|
||
import com.ucd.keynote.common.service.AuthService; | ||
import com.ucd.keynote.domain.notification.NotificationController; | ||
import com.ucd.keynote.domain.organization.dto.join.JoinRequestDTO; | ||
import com.ucd.keynote.domain.organization.dto.join.JoinRequestResponseDTO; | ||
import com.ucd.keynote.domain.organization.dto.join.JoinResponseDTO; | ||
import com.ucd.keynote.domain.organization.entity.Organization; | ||
import com.ucd.keynote.domain.organization.entity.UserOrganization; | ||
import com.ucd.keynote.domain.organization.entity.UserOrganizationId; | ||
import com.ucd.keynote.domain.organization.entity.join.OrganizationJoinRequest; | ||
import com.ucd.keynote.domain.organization.repository.OrganizationRepository; | ||
import com.ucd.keynote.domain.organization.repository.UserOrganizationRepository; | ||
import com.ucd.keynote.domain.organization.repository.join.OrganizationJoinRepository; | ||
import com.ucd.keynote.domain.user.entity.UserEntity; | ||
import lombok.AllArgsConstructor; | ||
import org.springframework.security.access.AccessDeniedException; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
@Service | ||
@AllArgsConstructor | ||
public class OrganizationJoinService { | ||
private final OrganizationJoinRepository organizationJoinRepository; | ||
private final OrganizationRepository organizationRepository; | ||
private final AuthService authService; | ||
private final UserOrganizationRepository userOrganizationRepository; | ||
private final NotificationController notificationController; | ||
|
||
// 가입 신청 처리 | ||
public JoinResponseDTO requestJoinOrganization(Long organizationId, JoinRequestDTO reqeust){ | ||
Organization organization = organizationRepository.findById(organizationId) | ||
.orElseThrow(() -> new IllegalArgumentException("조직이 존재하지 않습니다.")); | ||
UserEntity user = authService.getAuthenticatedUser(); | ||
|
||
// 사용자가 이미 조직에 속해 있는지 확인 | ||
boolean alreadyInOrganization = userOrganizationRepository.existsByOrganization_OrganizationIdAndUser_UserId(organizationId, user.getUserId()); | ||
if (alreadyInOrganization) { | ||
throw new IllegalStateException("사용자가 이미 조직에 속해 있습니다."); | ||
} | ||
|
||
// 이미 가입 신청이 존재하는지 확인(PENDING 상태) | ||
boolean alreadyRequested = organizationJoinRepository.existsByOrganization_OrganizationIdAndUser_UserIdAndStatus | ||
(organizationId, user.getUserId(), "PENDING"); | ||
if (alreadyRequested){ | ||
throw new IllegalArgumentException("이미 조직에 가입 신청을 보냈습니다."); | ||
} | ||
|
||
// 가입 신청 생성 | ||
OrganizationJoinRequest joinRequest = new OrganizationJoinRequest(); | ||
joinRequest.setOrganization(organization); | ||
joinRequest.setUser(user); | ||
joinRequest.setStatus("PENDING"); | ||
joinRequest.setRequestMessage(reqeust.getMessage()); | ||
joinRequest.setRequestedAt(LocalDateTime.now()); | ||
|
||
organizationJoinRepository.save(joinRequest); | ||
|
||
// 조직 내 관리자에게 알림 전송 | ||
List<UserOrganization> admins = userOrganizationRepository.findByOrganization_OrganizationIdAndRole(organizationId, "admin"); | ||
String notificationMessage = "새로운 가입 요청이 있습니다. 사용자: " + user.getUsername(); | ||
admins.forEach(admin -> notificationController.sendNotification(notificationMessage)); | ||
|
||
|
||
// 웅답 DTO 생성 | ||
return JoinResponseDTO.builder() | ||
.requestId(joinRequest.getId()) | ||
.organizationId(organization.getOrganizationId()) | ||
.status(joinRequest.getStatus()) | ||
.createdAt(joinRequest.getRequestedAt()) | ||
.build(); | ||
} | ||
|
||
// 이미 가입 신청이 존재하는지 확인(PENDING 상태) | ||
boolean alreadyRequested = organizationJoinRepository.existsByOrganization_OrganizationIdAndUser_UserIdAndStatus | ||
(organizationId, user.getUserId(), "PENDING"); | ||
if (alreadyRequested){ | ||
throw new IllegalArgumentException("이미 조직에 가입 신청을 보냈습니다."); | ||
// 가입 신청 목록 조회 | ||
public List<JoinRequestResponseDTO> getJoinRequests(Long organizationId){ | ||
List<OrganizationJoinRequest> joinRequests = organizationJoinRepository.findByOrganization_OrganizationIdAndStatus | ||
(organizationId, "PENDING"); | ||
return joinRequests.stream().map(request -> JoinRequestResponseDTO.builder() | ||
.requestId(request.getId()) | ||
.userId(request.getUser().getUserId()) | ||
.userName(request.getUser().getUsername()) | ||
.message(request.getRequestMessage()) | ||
.status(request.getStatus()) | ||
.requestedAt(request.getRequestedAt()) | ||
.build()).collect(Collectors.toList()); | ||
} | ||
|
||
// 가입 신청 생성 | ||
OrganizationJoinRequest joinRequest = new OrganizationJoinRequest(); | ||
joinRequest.setOrganization(organization); | ||
joinRequest.setUser(user); | ||
joinRequest.setStatus("PENDING"); | ||
joinRequest.setRequestMessage(reqeust.getMessage()); | ||
joinRequest.setRequestedAt(LocalDateTime.now()); | ||
|
||
organizationJoinRepository.save(joinRequest); | ||
|
||
// 웅답 DTO 생성 | ||
return JoinResponseDTO.builder() | ||
.requestId(joinRequest.getId()) | ||
.organizationId(organization.getOrganizationId()) | ||
.status(joinRequest.getStatus()) | ||
.createdAt(joinRequest.getRequestedAt()) | ||
.build(); | ||
} | ||
|
||
// 가입 신청 목록 조회 | ||
public List<JoinRequestResponseDTO> getJoinRequests(Long organizationId){ | ||
List<OrganizationJoinRequest> joinRequests = organizationJoinRepository.findByOrganization_OrganizationIdAndStatus | ||
(organizationId, "PENDING"); | ||
return joinRequests.stream().map(request -> JoinRequestResponseDTO.builder() | ||
.requestId(request.getId()) | ||
.userId(request.getUser().getUserId()) | ||
.userName(request.getUser().getUsername()) | ||
.message(request.getRequestMessage()) | ||
.status(request.getStatus()) | ||
.requestedAt(request.getRequestedAt()) | ||
.build()).collect(Collectors.toList()); | ||
} | ||
|
||
// 가입 요청 승인 | ||
@Transactional | ||
public void approveJoniRequest(Long organizationId, Long requestId){ | ||
// 사용자 권한 확인 | ||
UserEntity userEntity = authService.getAuthenticatedUser(); | ||
// 해당 조직에 admin 권한이 있는지 확인 | ||
UserOrganization Organization = userOrganizationRepository.findByOrganization_OrganizationIdAndUser_UserId(organizationId, userEntity.getUserId()) | ||
.orElseThrow(() -> new AccessDeniedException("이 조직에서 권한이 없습니다.")); | ||
//admin 권한 체크 | ||
if (!"admin".equals(Organization.getRole())) { | ||
throw new AccessDeniedException("admin 권한이 있어야 요청을 승인할 수 있습니다."); | ||
} | ||
|
||
// 가입 요청 가져오기 | ||
OrganizationJoinRequest joinRequest = organizationJoinRepository.findById(requestId) | ||
.orElseThrow(() -> new IllegalArgumentException("Join request not found")); | ||
|
||
// 이미 처리된 요청인지 확인 | ||
if (!"PENDING".equals(joinRequest.getStatus())){ | ||
throw new IllegalStateException("Join request has already been processed"); | ||
// 가입 요청 승인 | ||
@Transactional | ||
public void approveJoniRequest(Long organizationId, Long requestId){ | ||
// 사용자 권한 확인 | ||
UserEntity userEntity = authService.getAuthenticatedUser(); | ||
// 해당 조직에 admin 권한이 있는지 확인 | ||
UserOrganization Organization = userOrganizationRepository.findByOrganization_OrganizationIdAndUser_UserId(organizationId, userEntity.getUserId()) | ||
.orElseThrow(() -> new AccessDeniedException("이 조직에서 권한이 없습니다.")); | ||
//admin 권한 체크 | ||
if (!"admin".equals(Organization.getRole())) { | ||
throw new AccessDeniedException("admin 권한이 있어야 요청을 승인할 수 있습니다."); | ||
} | ||
|
||
// 가입 요청 가져오기 | ||
OrganizationJoinRequest joinRequest = organizationJoinRepository.findById(requestId) | ||
.orElseThrow(() -> new IllegalArgumentException("Join request not found")); | ||
|
||
// 이미 처리된 요청인지 확인 | ||
if (!"PENDING".equals(joinRequest.getStatus())){ | ||
throw new IllegalStateException("Join request has already been processed"); | ||
} | ||
|
||
// 조직 가져오기 | ||
Organization organization = organizationRepository.findById(organizationId) | ||
.orElseThrow(() -> new IllegalArgumentException("Organization not found")); | ||
|
||
System.out.println("get userId: " + joinRequest.getUser().getUserId()); | ||
System.out.println("get organization: " + organization.getOrganizationId()); | ||
|
||
// UserOrganizationId 설정 | ||
UserOrganizationId userOrganizationId = new UserOrganizationId(joinRequest.getUser().getUserId(), organization.getOrganizationId()); | ||
|
||
// 사용자를 조직에 추가 | ||
UserOrganization userOrganization = new UserOrganization(); | ||
userOrganization.setId(userOrganizationId); | ||
userOrganization.setUser(joinRequest.getUser()); | ||
userOrganization.setOrganization(organization); | ||
userOrganization.setRole("user"); | ||
userOrganization.setJoinedAt(LocalDateTime.now()); | ||
userOrganizationRepository.save(userOrganization); | ||
|
||
// 가입 요청 상태 변경 | ||
joinRequest.setStatus("APPROVED"); | ||
organizationJoinRepository.save(joinRequest); | ||
|
||
// 가입 요청 사용자에게 승인 알림 전송 | ||
String notificationMessage = "가입 요청이 승인되었습니다. 조직: " + organization.getOrganizationName(); | ||
notificationController.sendNotification(notificationMessage); | ||
} | ||
|
||
// 조직 가져오기 | ||
Organization organization = organizationRepository.findById(organizationId) | ||
.orElseThrow(() -> new IllegalArgumentException("Organization not found")); | ||
|
||
System.out.println("get userId: " + joinRequest.getUser().getUserId()); | ||
System.out.println("get organization: " + organization.getOrganizationId()); | ||
// 가입 요청 거절 | ||
public void rejectJoinRequest(Long organizationId, Long requestId){ | ||
// 현재 로그인 한 사용자 정보 받아오기 | ||
UserEntity userEntity = authService.getAuthenticatedUser(); | ||
|
||
// UserOrganizationId 설정 | ||
UserOrganizationId userOrganizationId = new UserOrganizationId(joinRequest.getUser().getUserId(), organization.getOrganizationId()); | ||
// 해당 조직에 admin 권한이 있는지 확인 | ||
UserOrganization userOrganization = userOrganizationRepository.findByOrganization_OrganizationIdAndUser_UserId(organizationId, userEntity.getUserId()) | ||
.orElseThrow(() -> new AccessDeniedException("이 조직에서 권한이 없습니다.")); | ||
//admin 권한 체크 | ||
if (!"admin".equals(userOrganization.getRole())) { | ||
throw new AccessDeniedException("admin 권한이 있어야 요청을 승인할 수 있습니다."); | ||
} | ||
|
||
// 사용자를 조직에 추가 | ||
UserOrganization userOrganization = new UserOrganization(); | ||
userOrganization.setId(userOrganizationId); | ||
userOrganization.setUser(joinRequest.getUser()); | ||
userOrganization.setOrganization(organization); | ||
userOrganization.setRole("user"); | ||
userOrganization.setJoinedAt(LocalDateTime.now()); | ||
userOrganizationRepository.save(userOrganization); | ||
// 가입 요청 조회 | ||
OrganizationJoinRequest joinRequest = organizationJoinRepository.findById(requestId) | ||
.orElseThrow(() -> new IllegalArgumentException("가입 요청을 찾을 수 없습니다.")); | ||
|
||
// 가입 요청 상태 변경 | ||
joinRequest.setStatus("APPROVED"); | ||
organizationJoinRepository.save(joinRequest); | ||
// 가입 요청 상태를 REJECTED로 변경 | ||
joinRequest.setStatus("REJECTED"); | ||
organizationJoinRepository.save(joinRequest); | ||
|
||
} | ||
|
||
|
||
// 가입 요청 거절 | ||
public void rejectJoinRequest(Long organizationId, Long requestId){ | ||
// 현재 로그인 한 사용자 정보 받아오기 | ||
UserEntity userEntity = authService.getAuthenticatedUser(); | ||
|
||
// 해당 조직에 admin 권한이 있는지 확인 | ||
UserOrganization userOrganization = userOrganizationRepository.findByOrganization_OrganizationIdAndUser_UserId(organizationId, userEntity.getUserId()) | ||
.orElseThrow(() -> new AccessDeniedException("이 조직에서 권한이 없습니다.")); | ||
//admin 권한 체크 | ||
if (!"admin".equals(userOrganization.getRole())) { | ||
throw new AccessDeniedException("admin 권한이 있어야 요청을 승인할 수 있습니다."); | ||
// 가입 요청 사용자에게 거절 알림 전송 | ||
String notificationMessage = "가입 요청이 거절되었습니다. 조직: " + joinRequest.getOrganization().getOrganizationName(); | ||
notificationController.sendNotification(notificationMessage); | ||
} | ||
|
||
// 가입 요청 조회 | ||
OrganizationJoinRequest joinRequest = organizationJoinRepository.findById(requestId) | ||
.orElseThrow(() -> new IllegalArgumentException("가입 요청을 찾을 수 없습니다.")); | ||
|
||
// 가입 요청 상태를 REJECTED로 변경 | ||
joinRequest.setStatus("REJECTED"); | ||
organizationJoinRepository.save(joinRequest); | ||
} | ||
|
||
} |