Skip to content

Commit

Permalink
refactor: 번쩍 모임 생성 시 모임 정보를 먼저 저장하도록 변경 완료 (#538)
Browse files Browse the repository at this point in the history
* refactor: meetingId 추가

* feat: 번쩍 모임 생성을 위해 모임 정보를 생성하는 createMeetingForLightning 메서드 추가

* feat: 번쩍 생성 시 최소한의 모임 정보를 생성하는 정적 팩토리 메서드 추가

* feat: 번쩍 모임 에러 코드 추가

* feat: 번쩍 모임 생성 시 기본 이미지 설정을 위한 Config 클래스 추가

* chore: yml에 이미지 환경변수 추가

* feat: 모임 id와 번쩍 생성 시 필요한 필드를 함께 포함한 DTO 생성

* refactor: 모임 정보를 먼저 생성하고 번쩍 정보를 생성하도록 변경

* refactor: 매퍼 매핑 로직 변경

* refactor: InStream을 사용하도록 변경

* chore: 404 예외 분리
  • Loading branch information
hoonyworld authored Jan 22, 2025
1 parent 66fdcb3 commit e53c032
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public class Lightning extends BaseTimeEntity {
@Column(name = "leaderUserId")
private Integer leaderUserId;

@NotNull
@Column(name = "meetingId")
private Integer meetingId;

@NotNull
@Size(min = 1, max = 30)
@Column(name = "title")
Expand Down Expand Up @@ -93,12 +97,14 @@ public class Lightning extends BaseTimeEntity {
private List<ImageUrlVO> imageURL;

@Builder
public Lightning(Integer leaderUserId, String title, String desc, LightningTimingType lightningTimingType,
public Lightning(Integer leaderUserId, Integer meetingId, String title, String desc,
LightningTimingType lightningTimingType,
LocalDateTime startDate, LocalDateTime endDate,
LocalDateTime activityStartDate, LocalDateTime activityEndDate, LightningPlaceType lightningPlaceType,
String lightningPlace, int minimumCapacity, int maximumCapacity, Integer createdGeneration,
List<ImageUrlVO> imageURL) {
this.leaderUserId = leaderUserId;
this.meetingId = meetingId;
this.title = title;
this.desc = desc;
this.lightningTimingType = lightningTimingType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,35 @@ public Meeting(User user, Integer userId, String title, MeetingCategory category
this.joinableParts = joinableParts;
}

public static Meeting createLightningMeeting(User user, Integer userId, String title,
List<ImageUrlVO> imageURL, LocalDateTime startDate,
LocalDateTime endDate, Integer capacity, String desc,
LocalDateTime mStartDate, LocalDateTime mEndDate,
int createdGeneration, String processDesc, String leaderDesc, String note) {

return Meeting.builder()
.user(user)
.userId(userId)
.title(title)
.category(MeetingCategory.LIGHTNING)
.imageURL(imageURL)
.startDate(startDate)
.endDate(endDate)
.capacity(capacity)
.desc(desc)
.mStartDate(mStartDate)
.mEndDate(mEndDate)
.createdGeneration(createdGeneration)
.processDesc(processDesc)
.leaderDesc(leaderDesc)
.note(note)
.isMentorNeeded(false)
.canJoinOnlyActiveGeneration(false)
.targetActiveGeneration(null)
.joinableParts(MeetingJoinablePart.values())
.build();
}

/**
* 모임 모집상태 확인
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.sopt.makers.crew.main.global.config;

public interface ImageSetting {
String getDefaultLightningImage();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.sopt.makers.crew.main.global.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ImageSettingConfig implements ImageSetting {
@Value("${img.lightning}")
private String defaultLightningImage;

@Override
public String getDefaultLightningImage() {
return defaultLightningImage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ public enum ErrorStatus {
VALIDATION_EXCEPTION("CF-001"),
VALIDATION_REQUEST_MISSING_EXCEPTION("요청값이 입력되지 않았습니다."),
INVALID_INPUT_VALUE_FILTER("요청값 또는 토큰이 올바르지 않습니다."),
NOT_FOUND_MEETING("모임이 없습니다."),
NOT_FOUND_POST("존재하지 않는 게시글입니다."),
NOT_FOUND_USER("존재하지 않는 유저입니다."),
NOT_FOUND_COMMENT("존재하지 않는 댓글입니다."),
FULL_MEETING_CAPACITY("정원이 꽉 찼습니다."),
ALREADY_APPLIED_MEETING("이미 지원한 모임입니다."),
ALREADY_REPORTED_COMMENT("이미 신고한 댓글입니다."),
Expand Down Expand Up @@ -63,6 +59,15 @@ public enum ErrorStatus {
*/
FORBIDDEN_EXCEPTION("권한이 없습니다."),

/**
* 404 NOT_FOUND
*/
NOT_FOUND_MEETING("모임이 없습니다."), // 예외 처리 NotFound로 수정 필요
NOT_FOUND_POST("존재하지 않는 게시글입니다."), // 예외 처리 NotFound로 수정 필요
NOT_FOUND_USER("존재하지 않는 유저입니다."), // 예외 처리 NotFound로 수정 필요
NOT_FOUND_COMMENT("존재하지 않는 댓글입니다."), // 예외 처리 NotFound로 수정 필요
NOT_FOUND_LIGHTNING("번쩍 모임이 없습니다."), // 예외 처리 NotFound로 수정 필요

/**
* 405 METHOD_NOT_ALLOWED
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
Expand All @@ -15,27 +15,25 @@
import org.sopt.makers.crew.main.entity.lightning.enums.LightningTimingType;
import org.sopt.makers.crew.main.entity.meeting.vo.ImageUrlVO;
import org.sopt.makers.crew.main.global.util.Time;
import org.sopt.makers.crew.main.lightning.v2.dto.request.LightningV2CreateLightningBodyWithoutWelcomeMessageDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2CreateMeetingForLightningResponseDto;

@Mapper(componentModel = "spring")
public interface LightningMapper {

@Mapping(source = "lightningBody.files", target = "imageURL", qualifiedByName = "getImageURL")
@Mapping(source = "lightningBody.activityStartDate", target = "activityStartDate", qualifiedByName = "getActivityStartDate")
@Mapping(source = "lightningBody.activityEndDate", target = "activityEndDate", qualifiedByName = "getActivityEndDate")
@Mapping(source = "lightningBody.lightningPlaceType", target = "lightningPlaceType", qualifiedByName = "getLightningPlaceType")
@Mapping(source = "lightningBody.lightningTimingType", target = "lightningTimingType", qualifiedByName = "getLightningTimingType")
@Mapping(source = "meetingV2CreateMeetingForLightningResponseDto.files", target = "imageURL", qualifiedByName = "getImageURL")
@Mapping(target = "startDate", expression = "java(time.now())")
@Mapping(source = "lightningBody.activityStartDate", target = "endDate", qualifiedByName = "getActivityStartDate")
Lightning toLightningEntity(LightningV2CreateLightningBodyWithoutWelcomeMessageDto lightningBody,
@Mapping(source = "meetingV2CreateMeetingForLightningResponseDto.activityStartDate", target = "endDate", qualifiedByName = "getActivityStartDate")
@Mapping(source = "meetingV2CreateMeetingForLightningResponseDto.activityStartDate", target = "activityStartDate", qualifiedByName = "getActivityStartDate")
@Mapping(source = "meetingV2CreateMeetingForLightningResponseDto.activityEndDate", target = "activityEndDate", qualifiedByName = "getActivityEndDate")
@Mapping(source = "meetingV2CreateMeetingForLightningResponseDto.lightningPlaceType", target = "lightningPlaceType", qualifiedByName = "getLightningPlaceType")
@Mapping(source = "meetingV2CreateMeetingForLightningResponseDto.lightningTimingType", target = "lightningTimingType", qualifiedByName = "getLightningTimingType")
Lightning toLightningEntity(
MeetingV2CreateMeetingForLightningResponseDto meetingV2CreateMeetingForLightningResponseDto,
Integer createdGeneration, Integer leaderUserId, Time time);

@Named("getImageURL")
static List<ImageUrlVO> getImageURL(List<String> files) {
AtomicInteger index = new AtomicInteger(0);

return files.stream()
.map(fileUrl -> new ImageUrlVO(index.getAndIncrement(), fileUrl))
return IntStream.range(0, files.size())
.mapToObj(index -> new ImageUrlVO(index, files.get(index)))
.toList();
}

Expand All @@ -47,7 +45,6 @@ static LocalDateTime getActivityStartDate(String date) {
@Named("getActivityEndDate")
static LocalDateTime getActivityEndDate(String date) {
return LocalDateTime.parse(date + DAY_END_TIME, DateTimeFormatter.ofPattern(DAY_TIME_FORMAT));

}

@Named("getLightningPlaceType")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.sopt.makers.crew.main.lightning.v2.dto.mapper.LightningMapper;
import org.sopt.makers.crew.main.lightning.v2.dto.request.LightningV2CreateLightningBodyDto;
import org.sopt.makers.crew.main.lightning.v2.dto.response.LightningV2CreateLightningResponseDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2CreateMeetingForLightningResponseDto;
import org.sopt.makers.crew.main.meeting.v2.service.MeetingV2Service;
import org.sopt.makers.crew.main.tag.v2.service.TagV2Service;
import org.sopt.makers.crew.main.user.v2.service.UserV2Service;
import org.springframework.stereotype.Service;
Expand All @@ -27,6 +29,7 @@ public class LightningV2ServiceImpl implements LightningV2Service {

private final UserV2Service userV2Service;
private final TagV2Service tagV2Service;
private final MeetingV2Service meetingV2Service;

private final LightningRepository lightningRepository;
private final LightningMapper lightningMapper;
Expand All @@ -47,12 +50,50 @@ public LightningV2CreateLightningResponseDto createLightning(
throw new BadRequestException(VALIDATION_EXCEPTION.getErrorCode());
}

Lightning lightning = lightningMapper.toLightningEntity(requestBody.lightningBody(), ACTIVE_GENERATION,
user.getId(), realTime);
MeetingV2CreateMeetingForLightningResponseDto meetingV2CreateMeetingForLightningResponseDto = meetingV2Service.createMeetingForLightning(
userId, requestBody.lightningBody());

Lightning lightning = lightningMapper.toLightningEntity(meetingV2CreateMeetingForLightningResponseDto,
ACTIVE_GENERATION, user.getId(), realTime);

lightningRepository.save(lightning);
tagV2Service.createLightningTag(requestBody.welcomeMessageTypes(), lightning.getId());

return LightningV2CreateLightningResponseDto.from(lightning.getId());
}

// @Override
// public LightningV2GetLightningByIdResponseDto getLightningById(Integer lightningId, Integer userId) {
// User user = userV2Service.getUserByUserId(userId);
//
// Lightning lightning = lightningRepository.findById(lightningId)
// .orElseThrow(() -> new NotFoundException(NOT_FOUND_LIGHTNING.getErrorCode()));
//
// lightning.
//
// Meeting meeting = meetingReader.getMeetingById(meetingId).toEntity();
// MeetingCreatorDto meetingLeader = userReader.getMeetingLeader(meeting.getUserId());
// CoLeaders coLeaders = coLeaderReader.getCoLeaders(meetingId).toEntity();
//
// Applies applies = new Applies(
// applyRepository.findAllByMeetingIdWithUser(meetingId, List.of(WAITING, APPROVE, REJECT), ORDER_ASC));
//
// Boolean isHost = meeting.checkMeetingLeader(user.getId());
// Boolean isApply = applies.isApply(meetingId, user.getId());
// Boolean isApproved = applies.isApproved(meetingId, user.getId());
// boolean isCoLeader = coLeaders.isCoLeader(meetingId, userId);
// long approvedCount = applies.getApprovedCount(meetingId);
//
// List<ApplyWholeInfoDto> applyWholeInfoDtos = new ArrayList<>();
// if (applies.hasApplies(meetingId)) {
// applyWholeInfoDtos = applies.getAppliesMap().get(meetingId).stream()
// .map(apply -> ApplyWholeInfoDto.of(apply, apply.getUser(), userId))
// .toList();
// }
//
// return LightningV2GetLightningByIdResponseDto.of(meetingId, meeting, coLeaders.getCoLeaders(meetingId),
// isCoLeader,
// approvedCount, isHost, isApply, isApproved,
// meetingLeader, applyWholeInfoDtos, realTime.now());
// }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.sopt.makers.crew.main.meeting.v2.dto.response;

import java.util.List;

import org.sopt.makers.crew.main.lightning.v2.dto.request.LightningV2CreateLightningBodyWithoutWelcomeMessageDto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

@Schema(name = "MeetingV2CreateMeetingForLightningResponseDto", description = "번쩍 모임 생성 및 수정 request body dto")
public record MeetingV2CreateMeetingForLightningResponseDto(
@Schema(description = "모임 id", example = "1")
@NotNull
Integer meetingId,

@Schema(example = "알고보면 쓸데있는 개발 프로세스", description = "번쩍 모임 제목")
@Size(min = 1, max = 30)
@NotNull String title,

@Schema(example = "api 가 터졌다고? 깃이 터졌다고?", description = "번쩍 소개")
@Size(min = 1, max = 500)
@NotNull
String desc,

@Schema(example = "예정 기간(협의 후 결정)", description = "번쩍 일정 결정 방식")
@NotNull
String lightningTimingType,

@Schema(example = "2025.10.29", description = "번쩍 활동 시작 날짜", name = "activityStartDate")
@NotNull
String activityStartDate,

@Schema(example = "2025.10.30", description = "번쩍 활동 종료 날짜", name = "activityEndDate")
@NotNull
String activityEndDate,

@Schema(example = "오프라인", description = "모임 장소 Tag")
@NotNull
String lightningPlaceType,

@Schema(example = "잠실역 5번 출구", description = "모임 장소")
String lightningPlace,

@Schema(example = "1", description = "최소 모집 인원")
@Min(1)
@NotNull
Integer minimumCapacity,

@Schema(example = "5", description = "최대 모집 인원")
@Min(1)
@Max(999)
@NotNull
Integer maximumCapacity,

@Schema(example = "[\n"
+ " \"https://makers-web-img.s3.ap-northeast-2.amazonaws.com/meeting/2023/04/12/7bd87736-b557-4b26-a0d5-9b09f1f1d7df\"\n"
+ " ]", description = "모임 이미지 리스트, 최대 1개")
@NotNull
@Size(max = 1)
List<String> files
) {
public static MeetingV2CreateMeetingForLightningResponseDto of(
Integer meetingId, LightningV2CreateLightningBodyWithoutWelcomeMessageDto lightningBody) {
return new MeetingV2CreateMeetingForLightningResponseDto(
meetingId,
lightningBody.title(),
lightningBody.desc(),
lightningBody.lightningTimingType(),
lightningBody.activityStartDate(),
lightningBody.activityEndDate(),
lightningBody.lightningPlaceType(),
lightningBody.lightningPlace(),
lightningBody.minimumCapacity(),
lightningBody.maximumCapacity(),
lightningBody.files()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import org.sopt.makers.crew.main.lightning.v2.dto.request.LightningV2CreateLightningBodyWithoutWelcomeMessageDto;
import org.sopt.makers.crew.main.meeting.v2.dto.query.MeetingGetAppliesQueryDto;
import org.sopt.makers.crew.main.meeting.v2.dto.query.MeetingV2GetAllMeetingByOrgUserQueryDto;
import org.sopt.makers.crew.main.meeting.v2.dto.query.MeetingV2GetAllMeetingQueryDto;
Expand All @@ -11,6 +12,7 @@
import org.sopt.makers.crew.main.meeting.v2.dto.response.AppliesCsvFileUrlResponseDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingGetApplyListResponseDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2ApplyMeetingResponseDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2CreateMeetingForLightningResponseDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2CreateMeetingResponseDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2GetAllMeetingByOrgUserDto;
import org.sopt.makers.crew.main.meeting.v2.dto.response.MeetingV2GetAllMeetingDto;
Expand Down Expand Up @@ -50,4 +52,7 @@ AppliesCsvFileUrlResponseDto getAppliesCsvFileUrl(Integer meetingId, List<Intege
MeetingV2GetMeetingByIdResponseDto getMeetingById(Integer meetingId, Integer userId);

MeetingV2GetRecommendDto getRecommendMeetingsByIds(List<Integer> meetingIds, Integer userId);

MeetingV2CreateMeetingForLightningResponseDto createMeetingForLightning(Integer userId,
LightningV2CreateLightningBodyWithoutWelcomeMessageDto lightningBody);
}
Loading

0 comments on commit e53c032

Please sign in to comment.