Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ public void validateVerificationCode(String email, String code) {

@Transactional
public void register(RegisterRequest registerRequest) {
checkEmailDuplicate(registerRequest.email());
checkPhoneDuplicate(registerRequest.phone());
checkIdDuplicate(registerRequest.id());

validateAndDeleteEmailVerification(registerRequest.email());

User user = User.builder()
Expand All @@ -107,6 +111,8 @@ public void register(RegisterRequest registerRequest) {

@Transactional
public void oauthRegister(OAuthRegisterRequest oAuthRegisterRequest) {
checkEmailDuplicate(oAuthRegisterRequest.email());
checkPhoneDuplicate(oAuthRegisterRequest.phone());
validateAndDeleteEmailVerification(oAuthRegisterRequest.email());

User user = User.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public class SecurityConfig {
"/swagger-resources/**",
"/webjars/**",
"/actuator/**",
"/papers/invite"
"/papers/invite",
"/invites/**/comments",
};

private static final String[] BLACKLIST = {
Expand Down Expand Up @@ -90,8 +91,6 @@ public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager
.requestMatchers(WHITELIST).permitAll()
.requestMatchers(HttpMethod.POST, "/reports").hasAuthority(Role.USER.getRole())
.requestMatchers(HttpMethod.GET, "/invites/**").permitAll()
.requestMatchers(HttpMethod.POST, "/invites").hasAuthority(Role.USER.getRole())
.requestMatchers(HttpMethod.POST, "/invites/**/comments").hasAuthority(Role.USER.getRole())
.requestMatchers(BLACKLIST).authenticated()
.anyRequest().authenticated())
.addFilterAt(new CustomUserLoginFilter(authenticationManager, tokenProvider, objectMapper),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package doldol_server.doldol.invite.controller;

import doldol_server.doldol.auth.dto.CustomUserDetails;
import doldol_server.doldol.common.response.ApiResponse;
import doldol_server.doldol.auth.dto.CustomUserDetails;
import doldol_server.doldol.invite.dto.request.InviteCommentCreateRequest;
import doldol_server.doldol.invite.dto.request.InviteCreateRequest;
import doldol_server.doldol.invite.dto.request.InviteUpdateRequest;
import doldol_server.doldol.invite.dto.response.InviteCommentResponse;
import doldol_server.doldol.invite.dto.response.InviteResponse;
import doldol_server.doldol.invite.service.InviteService;
Expand All @@ -17,7 +18,7 @@

import java.util.List;

@Tag(name = "Invite", description = "파티/모임 초대장 API")
@Tag(name = "초대장", description = "파티/모임 초대장 API")
@RestController
@RequestMapping("/invites")
@RequiredArgsConstructor
Expand All @@ -43,23 +44,46 @@ public ApiResponse<InviteResponse> getInvite(@PathVariable Long inviteId) {
return ApiResponse.ok(inviteService.getInvite(inviteId));
}

@Operation(
summary = "초대장 댓글 등록",
security = {@SecurityRequirement(name = "jwt")}
)
@Operation(summary = "초대장 댓글 등록")
@PostMapping("/{inviteId}/comments")
public ApiResponse<InviteCommentResponse> addComment(
@PathVariable Long inviteId,
@Valid @RequestBody InviteCommentCreateRequest request,
@AuthenticationPrincipal CustomUserDetails userDetails
@Valid @RequestBody InviteCommentCreateRequest request
) {
return ApiResponse.created(inviteService.addComment(inviteId, request, userDetails.getUserId()));
return ApiResponse.created(inviteService.addComment(inviteId, request));
}

@Operation(summary = "초대장 댓글 목록 조회")
@GetMapping("/{inviteId}/comments")
public ApiResponse<List<InviteCommentResponse>> getComments(@PathVariable Long inviteId) {
return ApiResponse.ok(inviteService.getComments(inviteId));
}

@Operation(
summary = "초대장 수정",
security = {@SecurityRequirement(name = "jwt")}
)
@PutMapping("/{inviteId}")
public ApiResponse<Void> updateInvite(
@PathVariable Long inviteId,
@Valid @RequestBody InviteUpdateRequest request,
@AuthenticationPrincipal CustomUserDetails userDetails
) {
inviteService.updateInvite(inviteId, request, userDetails.getUserId());
return ApiResponse.noContent();
}

@Operation(
summary = "초대장 삭제",
security = {@SecurityRequirement(name = "jwt")}
)
@DeleteMapping("/{inviteId}")
public ApiResponse<Void> deleteInvite(
@PathVariable Long inviteId,
@AuthenticationPrincipal CustomUserDetails userDetails
) {
inviteService.deleteInvite(inviteId, userDetails.getUserId());
return ApiResponse.noContent();
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package doldol_server.doldol.invite.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
Expand All @@ -21,7 +20,6 @@ public class InviteCreateRequest {

@Schema(description = "행사 일시", example = "2025-12-31T18:30:00")
@NotNull(message = "일시는 필수입니다.")
@FutureOrPresent(message = "과거 일시는 입력할 수 없습니다.")
private LocalDateTime eventDateTime;

@Schema(description = "행사 장소", example = "서울시 강남구 역삼동 123-45")
Expand All @@ -35,12 +33,10 @@ public class InviteCreateRequest {

@Schema(description = "초대장 본문 문구", example = "함께 모여 즐거운 시간을 보내요!")
@NotBlank(message = "문구는 필수입니다.")
@Size(max = 1000, message = "문구는 1000자를 초과할 수 없습니다.")
private String content;

@Schema(description = "보내는 사람 또는 단체 명", example = "돌돌팀")
@NotBlank(message = "보내는 사람은 필수입니다.")
@Size(max = 60, message = "보내는 사람은 60자를 초과할 수 없습니다.")
private String sender;

@Schema(description = "초대장 테마", example = "retro")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package doldol_server.doldol.invite.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class InviteUpdateRequest {

private static final String TITLE_MESSAGE = "제목은 1자 이상 40자 이하여야 합니다.";

@Schema(description = "초대장 제목", example = "돌돌이의 홈파티")
@NotBlank(message = TITLE_MESSAGE)
@Size(max = 40, message = TITLE_MESSAGE)
private String title;

@Schema(description = "행사 일시", example = "2025-12-31T18:30:00")
@NotNull(message = "일시는 필수입니다.")
private LocalDateTime eventDateTime;

@Schema(description = "행사 장소", example = "서울시 강남구 역삼동 123-45")
@NotBlank(message = "장소는 필수입니다.")
@Size(max = 120, message = "장소는 120자를 초과할 수 없습니다.")
private String location;

@Schema(description = "장소 링크", example = "https://maps.google.com/?q=서울시+강남구")
private String locationLink;

@Schema(description = "초대장 본문 문구", example = "함께 모여 즐거운 시간을 보내요!")
@NotBlank(message = "문구는 필수입니다.")
private String content;

@Schema(description = "보내는 사람 또는 단체 명", example = "돌돌팀")
@NotBlank(message = "보내는 사람은 필수입니다.")
@Size(max = 60, message = "보내는 사람은 60자를 초과할 수 없습니다.")
private String sender;

@Schema(description = "초대장 테마", example = "retro")
@Size(max = 30, message = "테마는 30자를 초과할 수 없습니다.")
private String theme;

@Schema(description = "폰트 스타일", example = "Arial")
@NotBlank(message = "폰트 스타일은 필수입니다.")
private String fontStyle;

}

Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ public class InviteCommentResponse {
@Schema(description = "댓글 작성자", example = "돌돌이 친구들")
private final String author;

@Schema(description = "댓글 작성자 ID", example = "1")
private final Long userId;

@Schema(description = "댓글 작성자 이름", example = "홍길동")
private final String userName;

@Schema(description = "댓글 내용", example = "꼭 참석할게요!")
private final String content;

Expand All @@ -33,8 +27,6 @@ public static InviteCommentResponse from(InviteComment comment) {
return InviteCommentResponse.builder()
.commentId(comment.getCommentId())
.author(comment.getAuthor())
.userId(comment.getUser().getId())
.userName(comment.getUser().getName())
.content(comment.getContent())
.createdAt(comment.getCreatedAt())
.build();
Expand Down
29 changes: 17 additions & 12 deletions src/main/java/doldol_server/doldol/invite/entity/Invite.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,31 @@
@Entity
public class Invite extends BaseEntity {

private static final int TITLE_MAX_LENGTH = 40;
private static final int LOCATION_MAX_LENGTH = 120;
private static final int SENDER_MAX_LENGTH = 60;
private static final int CODE_MAX_LENGTH = 36;
private static final int THEME_MAX_LENGTH = 30;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long inviteId;

@Column(nullable = false)
private LocalDateTime eventDateTime;

@Column(nullable = false, length = LOCATION_MAX_LENGTH)
@Column(nullable = false)
private String location;

@Column(name = "location_link", length = 500)
@Column(name = "location_link")
private String locationLink;

@Column(nullable = false, length = 1000)
private String content;

@Column(nullable = false, length = TITLE_MAX_LENGTH)
@Column(nullable = false)
private String title;

@Column(nullable = false, length = SENDER_MAX_LENGTH)
@Column(nullable = false)
private String sender;

@Column(nullable = false, unique = true, length = CODE_MAX_LENGTH)
@Column(nullable = false, unique = true)
private String inviteCode;

@Column(length = THEME_MAX_LENGTH)
private String theme;

@Column(name = "font_style", nullable = false)
Expand Down Expand Up @@ -81,5 +74,17 @@ public void addComment(InviteComment comment) {
comments.add(comment);
comment.assignInvite(this);
}

public void update(String title, LocalDateTime eventDateTime, String location, String locationLink,
String content, String sender, String theme, String fontStyle) {
this.title = title;
this.eventDateTime = eventDateTime;
this.location = location;
this.locationLink = locationLink;
this.content = content;
this.sender = sender;
this.theme = theme;
this.fontStyle = fontStyle;
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package doldol_server.doldol.invite.entity;

import doldol_server.doldol.common.entity.BaseEntity;
import doldol_server.doldol.user.entity.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
Expand All @@ -14,7 +13,6 @@
@Entity
public class InviteComment extends BaseEntity {

private static final int AUTHOR_MAX_LENGTH = 40;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -24,21 +22,14 @@ public class InviteComment extends BaseEntity {
@JoinColumn(name = "invite_id", nullable = false)
private Invite invite;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", referencedColumnName = "user_id", nullable = false)
private User user;

@Column(length = AUTHOR_MAX_LENGTH)
private String author;

@Column(nullable = false, length = 500)
private String content;

@Builder
private InviteComment(String author, String content, User user) {
private InviteComment(String author, String content) {
this.author = author;
this.content = content;
this.user = user;
}

void assignInvite(Invite invite) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
@AllArgsConstructor
public enum InviteErrorCode implements ErrorCode {

INVITE_NOT_FOUND(HttpStatus.NOT_FOUND, "IV-001", "초대장을 찾을 수 없습니다.");
INVITE_NOT_FOUND(HttpStatus.NOT_FOUND, "IV-001", "초대장을 찾을 수 없습니다."),
INVITE_FORBIDDEN(HttpStatus.FORBIDDEN, "IV-002", "초대장을 수정하거나 삭제할 권한이 없습니다.");

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import doldol_server.doldol.common.exception.CustomException;
import doldol_server.doldol.invite.dto.request.InviteCommentCreateRequest;
import doldol_server.doldol.invite.dto.request.InviteCreateRequest;
import doldol_server.doldol.invite.dto.request.InviteUpdateRequest;
import doldol_server.doldol.invite.dto.response.InviteCommentResponse;
import doldol_server.doldol.invite.dto.response.InviteResponse;
import doldol_server.doldol.invite.entity.Invite;
Expand Down Expand Up @@ -58,17 +59,13 @@ public InviteResponse getInvite(Long inviteId) {
}

@Transactional
public InviteCommentResponse addComment(Long inviteId, InviteCommentCreateRequest request, Long userId) {
public InviteCommentResponse addComment(Long inviteId, InviteCommentCreateRequest request) {
Invite invite = inviteRepository.findById(inviteId)
.orElseThrow(() -> new CustomException(InviteErrorCode.INVITE_NOT_FOUND));

User user = userRepository.findById(userId)
.orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND));

InviteComment comment = InviteComment.builder()
.author(request.getAuthor())
.content(request.getContent())
.user(user)
.build();
invite.addComment(comment);
inviteCommentRepository.save(comment);
Expand All @@ -85,5 +82,38 @@ public List<InviteCommentResponse> getComments(Long inviteId) {
.map(InviteCommentResponse::from)
.toList();
}

@Transactional
public void updateInvite(Long inviteId, InviteUpdateRequest request, Long userId) {
Invite invite = inviteRepository.findById(inviteId)
.orElseThrow(() -> new CustomException(InviteErrorCode.INVITE_NOT_FOUND));

if (!invite.getUser().getId().equals(userId)) {
throw new CustomException(InviteErrorCode.INVITE_FORBIDDEN);
}

invite.update(
request.getTitle(),
request.getEventDateTime(),
request.getLocation(),
request.getLocationLink(),
request.getContent(),
request.getSender(),
request.getTheme(),
request.getFontStyle()
);
}

@Transactional
public void deleteInvite(Long inviteId, Long userId) {
Invite invite = inviteRepository.findById(inviteId)
.orElseThrow(() -> new CustomException(InviteErrorCode.INVITE_NOT_FOUND));

if (!invite.getUser().getId().equals(userId)) {
throw new CustomException(InviteErrorCode.INVITE_FORBIDDEN);
}

inviteRepository.delete(invite);
}
}

Loading