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 @@ -23,7 +23,8 @@ public class CreateLetterRequest {
@Schema(description = "편지 내용(360자 이하)", example = "요즘 자꾸 불안해져서... 누가 한마디 해주면 좋겠어.")
private String text;


@Schema(description = "배경 기본은 하얀색", example = "WHITE", nullable = true)
@NotNull
private PlazaLetterColor backgroundColor;

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ public record CreateLetterResponse(
PlazaLetterMode mode,
String fromLabel,
String backgroundColor,
OffsetDateTime createdAt
) {}
OffsetDateTime createdAt,
String backgroundImageUrl
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public enum LettersErrorCode implements BaseErrorCode {
INVALID_REPORT_REASON(HttpStatus.BAD_REQUEST, "PLAZA400_INVALID_REPORT_REASON", "잘못된 신고 사유입니다."),
ALREADY_REPORTED(HttpStatus.BAD_REQUEST, "PLAZA400_ALREADY_REPORTED", "이미 신고한 답장입니다."),
NOT_FRIEND(HttpStatus.BAD_REQUEST, "PLAZA400_NOT_FRIEND", "친구 관계가 아닙니다."),
INSUFFICIENT_INK(HttpStatus.BAD_REQUEST, "PLAZA400_INSUFFICIENT_INK", "잉크가 부족합니다."),





Expand All @@ -34,6 +37,7 @@ public enum LettersErrorCode implements BaseErrorCode {
USER_NOT_FOUND(HttpStatus.NOT_FOUND,"PLAZA404_USER_NOT_FOUND", "유저를 찾을 수 없어요."),



// 409
ALREADY_REPLIED(HttpStatus.CONFLICT, "PLAZA409_ALREADY_REPLIED", "이미 답장한 편지예요"),
ALREADY_GAVE_UP(HttpStatus.CONFLICT, "PLAZA409_ALREADY_GAVE_UP", "24시간이 지나 답장할 수 없어요"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ public enum PlazaLetterColor {
public int getPrice() {
return price;
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Value;


import java.time.*;
Expand Down Expand Up @@ -66,6 +67,10 @@ public class PlazaLetterService {

private final NotificationService notificationService;

@Value("${spring.cloud.aws.cloudfront.domain}")
private String cloudfrontDomain;


@Transactional(readOnly = true)
public InboxNextResponse getNextArrivedLetter(Long userId) {
return plazaLetterRepository
Expand Down Expand Up @@ -118,8 +123,35 @@ public CreateLetterResponse createLetter(Long userId, CreateLetterRequest reques
}
}

// =========================
// 편지지 색상/잉크 결제 로직
// - null 또는 WHITE => WHITE로 확정, price=0, 차감 없음
// - 유료 색상 => 잉크 부족 체크 + 차감 + 로그
// =========================
// 1. 색상 안전 처리
PlazaLetterColor color =
(request.getBackgroundColor() == null)
? PlazaLetterColor.WHITE
: request.getBackgroundColor();

// 2. 가격 조회
int price = color.getPrice(); // WHITE면 0

// 3. 잉크 차감 (유료일 때만)
if (price > 0) {
user.usingInk(price); // 부족하면 여기서 예외 발생

InkLog inkLog = InkLog.builder()
.user(user)
.amount(-price)
.reason(InkLogType.LETTER_COLOR_PURCHASE)
.build();

inkLogRepository.save(inkLog);
}


PlazaLetterThread thread = plazaLetterThreadRepository.save(PlazaLetterThread.createNow());
String bg = request.getBackgroundColor() == null ? "WHITE" : request.getBackgroundColor().name();

String fromLabel = "익명";
if (request.getMode() == PlazaLetterMode.FRIEND) {
Expand Down Expand Up @@ -162,11 +194,11 @@ public CreateLetterResponse createLetter(Long userId, CreateLetterRequest reques
.mode(request.getMode())
.fromLabel(fromLabel)
.content(request.getText())
.backgroundColor(PlazaLetterColor.valueOf(bg))
.status(status) // ARRIVED or WAITING
.backgroundColor(color)
.status(status)
.createdAt(now)
.arrivedAt(arrivedAt) // WAITING이면 null
.replyDeadlineAt(replyDeadlineAt) // WAITING이면 null
.arrivedAt(arrivedAt)
.replyDeadlineAt(replyDeadlineAt)
.build();

// =================================================
Expand Down Expand Up @@ -216,13 +248,22 @@ public CreateLetterResponse createLetter(Long userId, CreateLetterRequest reques
letter.getSenderId(), saved.getLetterId(), e);
}


String imageUrl = null;
if (saved.getBackgroundColor() != PlazaLetterColor.WHITE) {
String fileName = saved.getBackgroundColor().name().substring(0, 1)
+ saved.getBackgroundColor().name().substring(1).toLowerCase();
imageUrl = cloudfrontDomain + "/letter/" + fileName + ".png";
}

return CreateLetterResponse.builder()
.letterId(saved.getLetterId())
.threadId(saved.getThreadId())
.status(saved.getStatus())
.mode(saved.getMode())
.fromLabel(saved.getFromLabel())
.backgroundColor(saved.getBackgroundColor().name())
.backgroundImageUrl(imageUrl)
.createdAt(saved.getCreatedAt())
.build();
}
Expand Down Expand Up @@ -269,19 +310,30 @@ private PlazaLetterColor resolveBackgroundColor(String requested) {
}



private void validateCreateLetterRequest(CreateLetterRequest request) {
if (request == null || request.getMode() == null) {
if (request == null) {
throw new CustomException(LettersErrorCode.INVALID_MODE);
}

if (request.getMode() == null) {
throw new CustomException(LettersErrorCode.INVALID_MODE);
}

String text = request.getText();
if (text == null || text.isBlank() || text.length() > LETTER_TEXT_LIMIT) {
throw new CustomException(LettersErrorCode.LETTER_TEXT_LIMIT);
}

if (request.getMode() == PlazaLetterMode.FRIEND && request.getToFriendId() == null) {
throw new CustomException(LettersErrorCode.FRIEND_ID_REQUIRED);
}

// backgroundColor는 null 허용.
// null/WHITE면 이후 createLetter에서 WHITE로 보정 + price=0 처리함.
}


@Transactional
public DeleteThreadResponse deleteThread(Long userId, Long threadId) {
// 스레드 존재 체크
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public enum InkLogType {
DAILY_MISSION_REWARD,
WEEKLY_MISSION_REWARD,
WATCH_AD,
WEEKLY_UNLOCK
WEEKLY_UNLOCK,
LETTER_COLOR_PURCHASE
}
12 changes: 12 additions & 0 deletions src/main/java/com/example/egobook_be/domain/user/entity/User.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.example.egobook_be.domain.user.entity;

import com.example.egobook_be.domain.ego_room.enums.CounselTone;
import com.example.egobook_be.domain.letters.enums.LettersErrorCode;
import com.example.egobook_be.domain.shop.entity.UserItem;
import com.example.egobook_be.domain.user.enums.RoleType;
import com.example.egobook_be.domain.user.enums.UserStatus;
import com.example.egobook_be.global.entity.BaseTimeEntity;
import com.example.egobook_be.global.exception.CustomException;
import jakarta.persistence.*;
import lombok.*;

Expand Down Expand Up @@ -173,6 +175,16 @@ public void useInk(int price){
this.ink -= price;
}

public void usingInk(int price){
if (price <= 0) return;

if (this.ink == null || this.ink < price) {
throw new CustomException(LettersErrorCode.INSUFFICIENT_INK);
}

this.ink -= price;
}

public void updateNotificationEnabled() {
this.notificationEnabled = !this.notificationEnabled;
}
Expand Down
Loading