mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 08:19:10 +00:00
회의 참석자 초대 API 개발
This commit is contained in:
@@ -6,6 +6,7 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -106,4 +107,14 @@ public class Meeting {
|
||||
public boolean isInProgress() {
|
||||
return "IN_PROGRESS".equals(this.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 참석자 추가
|
||||
*/
|
||||
public void addParticipant(String participantEmail) {
|
||||
if (this.participants == null) {
|
||||
this.participants = new ArrayList<>();
|
||||
}
|
||||
this.participants.add(participantEmail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ public class MeetingService implements
|
||||
StartMeetingUseCase,
|
||||
EndMeetingUseCase,
|
||||
CancelMeetingUseCase,
|
||||
GetMeetingUseCase {
|
||||
GetMeetingUseCase,
|
||||
InviteParticipantUseCase {
|
||||
|
||||
private final MeetingReader meetingReader;
|
||||
private final MeetingWriter meetingWriter;
|
||||
@@ -200,4 +201,43 @@ public class MeetingService implements
|
||||
|
||||
return meetingReader.findByOrganizerIdAndStatus(organizerId, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 회의 참석자 초대
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void inviteParticipant(InviteParticipantCommand command) {
|
||||
log.info("Inviting participant to meeting: {}, email: {}", command.meetingId(), command.email());
|
||||
|
||||
// 회의 조회
|
||||
Meeting meeting = meetingReader.findById(command.meetingId())
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));
|
||||
|
||||
// 회의 상태 검증 (예약됨 또는 진행중인 회의만 초대 가능)
|
||||
if ("COMPLETED".equals(meeting.getStatus()) || "CANCELLED".equals(meeting.getStatus())) {
|
||||
throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
|
||||
}
|
||||
|
||||
// 이미 참석자로 등록되었는지 확인
|
||||
if (meeting.getParticipants() != null && meeting.getParticipants().contains(command.email())) {
|
||||
log.warn("Email {} is already a participant of meeting {}", command.email(), command.meetingId());
|
||||
throw new BusinessException(ErrorCode.DUPLICATE_RESOURCE);
|
||||
}
|
||||
|
||||
// 참석자 목록에 추가
|
||||
meeting.addParticipant(command.email());
|
||||
|
||||
// 저장
|
||||
meetingWriter.save(meeting);
|
||||
|
||||
// TODO: 실제 이메일 발송 구현 필요
|
||||
// 이메일 발송 서비스 호출
|
||||
// emailService.sendInvitation(command.email(), meeting, command.frontendUrl());
|
||||
// 현재는 로그만 남기고 성공으로 처리
|
||||
log.info("Invitation email would be sent to {} for meeting {} (Frontend URL: {})",
|
||||
command.email(), meeting.getTitle(), command.frontendUrl());
|
||||
|
||||
log.info("Participant invited successfully: {} to meeting {}", command.email(), command.meetingId());
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.unicorn.hgzero.meeting.biz.usecase.in.meeting;
|
||||
|
||||
/**
|
||||
* 회의 참석자 초대 UseCase
|
||||
*/
|
||||
public interface InviteParticipantUseCase {
|
||||
|
||||
/**
|
||||
* 회의 참석자 초대
|
||||
* 이메일로 초대장 발송
|
||||
*/
|
||||
void inviteParticipant(InviteParticipantCommand command);
|
||||
|
||||
/**
|
||||
* 참석자 초대 명령
|
||||
*/
|
||||
record InviteParticipantCommand(
|
||||
String meetingId,
|
||||
String email,
|
||||
String inviterName,
|
||||
String frontendUrl
|
||||
) {}
|
||||
}
|
||||
+52
@@ -4,7 +4,9 @@ import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import com.unicorn.hgzero.meeting.biz.dto.MeetingDTO;
|
||||
import com.unicorn.hgzero.meeting.biz.usecase.in.meeting.*;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.request.CreateMeetingRequest;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.request.InviteParticipantRequest;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.request.SelectTemplateRequest;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.InviteParticipantResponse;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.MeetingResponse;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.SessionResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -35,6 +37,7 @@ public class MeetingController {
|
||||
private final EndMeetingUseCase endMeetingUseCase;
|
||||
private final GetMeetingUseCase getMeetingUseCase;
|
||||
private final CancelMeetingUseCase cancelMeetingUseCase;
|
||||
private final InviteParticipantUseCase inviteParticipantUseCase;
|
||||
|
||||
/**
|
||||
* 회의 예약
|
||||
@@ -241,4 +244,53 @@ public class MeetingController {
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 회의 참석자 초대
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param userId 사용자 ID
|
||||
* @param userName 사용자명
|
||||
* @param userEmail 사용자 이메일
|
||||
* @param request 참석자 초대 요청
|
||||
* @return 초대 결과
|
||||
*/
|
||||
@Operation(
|
||||
summary = "회의 참석자 초대",
|
||||
description = "진행 중이거나 예약된 회의에 새로운 참석자를 초대합니다. 초대된 참석자에게는 회의록 프론트엔드 URL과 함께 이메일이 발송됩니다.",
|
||||
security = @SecurityRequirement(name = "bearerAuth")
|
||||
)
|
||||
@PostMapping("/{meetingId}/invite")
|
||||
public ResponseEntity<ApiResponse<InviteParticipantResponse>> inviteParticipant(
|
||||
@Parameter(description = "회의 ID", required = true)
|
||||
@PathVariable String meetingId,
|
||||
@Parameter(description = "사용자 ID", required = true)
|
||||
@RequestHeader("X-User-Id") String userId,
|
||||
@Parameter(description = "사용자명", required = true)
|
||||
@RequestHeader("X-User-Name") String userName,
|
||||
@Parameter(description = "사용자 이메일", required = true)
|
||||
@RequestHeader("X-User-Email") String userEmail,
|
||||
@Valid @RequestBody InviteParticipantRequest request) {
|
||||
|
||||
log.info("참석자 초대 요청 - meetingId: {}, email: {}, inviter: {}",
|
||||
meetingId, request.getEmail(), userName);
|
||||
|
||||
// 프론트엔드 URL 생성 (실제 환경에서는 설정에서 가져와야 함)
|
||||
String frontendUrl = "https://meeting.hgzero.com/meeting/" + meetingId;
|
||||
|
||||
inviteParticipantUseCase.inviteParticipant(
|
||||
new InviteParticipantUseCase.InviteParticipantCommand(
|
||||
meetingId,
|
||||
request.getEmail(),
|
||||
userName,
|
||||
frontendUrl
|
||||
)
|
||||
);
|
||||
|
||||
var response = InviteParticipantResponse.of(meetingId, request.getEmail());
|
||||
|
||||
log.info("참석자 초대 완료 - meetingId: {}, email: {}", meetingId, request.getEmail());
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.unicorn.hgzero.meeting.infra.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 참석자 초대 요청 DTO
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "참석자 초대 요청")
|
||||
public class InviteParticipantRequest {
|
||||
|
||||
@NotBlank(message = "이메일 주소는 필수입니다")
|
||||
@Email(message = "올바른 이메일 형식이 아닙니다")
|
||||
@Schema(description = "초대할 참석자 이메일", example = "newparticipant@example.com", required = true)
|
||||
private String email;
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.unicorn.hgzero.meeting.infra.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 참석자 초대 응답 DTO
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "참석자 초대 응답")
|
||||
public class InviteParticipantResponse {
|
||||
|
||||
@Schema(description = "회의 ID", example = "123e4567-e89b-12d3-a456-426614174000")
|
||||
private String meetingId;
|
||||
|
||||
@Schema(description = "초대된 참석자 이메일", example = "newparticipant@example.com")
|
||||
private String invitedEmail;
|
||||
|
||||
@Schema(description = "초대 성공 여부", example = "true")
|
||||
private boolean success;
|
||||
|
||||
@Schema(description = "메시지", example = "참석자 초대가 완료되었습니다. 이메일을 확인해주세요.")
|
||||
private String message;
|
||||
|
||||
public static InviteParticipantResponse of(String meetingId, String email) {
|
||||
return new InviteParticipantResponse(
|
||||
meetingId,
|
||||
email,
|
||||
true,
|
||||
"참석자 초대가 완료되었습니다. 이메일을 확인해주세요."
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user