diff --git a/build.gradle b/build.gradle index 2a1da05b..469a4512 100644 --- a/build.gradle +++ b/build.gradle @@ -61,6 +61,9 @@ dependencies { // sms api implementation 'net.nurigo:sdk:4.3.0' + + // test db + testRuntimeOnly 'com.h2database:h2' } tasks.named('test') { diff --git a/src/main/java/hyundai/softeer/orange/common/ErrorCode.java b/src/main/java/hyundai/softeer/orange/common/ErrorCode.java index aef55ddb..55a0243b 100644 --- a/src/main/java/hyundai/softeer/orange/common/ErrorCode.java +++ b/src/main/java/hyundai/softeer/orange/common/ErrorCode.java @@ -34,6 +34,7 @@ public enum ErrorCode { EVENT_FRAME_NOT_FOUND(HttpStatus.NOT_FOUND, false, "이벤트 프레임을 찾을 수 없습니다."), EVENT_USER_NOT_FOUND(HttpStatus.NOT_FOUND, false, "이벤트 사용자를 찾을 수 없습니다."), COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, false, "기대평을 찾을 수 없습니다."), + EVENT_NOT_FOUND(HttpStatus.NOT_FOUND, false, "이벤트를 찾을 수 없습니다."), // 405 Method Not Allowed METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, false, "허용되지 않은 메서드입니다."), diff --git a/src/main/java/hyundai/softeer/orange/common/GlobalExceptionHandler.java b/src/main/java/hyundai/softeer/orange/common/GlobalExceptionHandler.java index f8aaf25b..f442fb9a 100644 --- a/src/main/java/hyundai/softeer/orange/common/GlobalExceptionHandler.java +++ b/src/main/java/hyundai/softeer/orange/common/GlobalExceptionHandler.java @@ -38,4 +38,9 @@ public ResponseEntity> handleInValidRequestException(MethodA public ResponseEntity handleException(BaseException e) { return ResponseEntity.status(e.getErrorCode().getHttpStatus()).body(ErrorResponse.from(e.getErrorCode())); } + + @ExceptionHandler({BaseException.class}) + public ResponseEntity handleAllBaseException(BaseException e) { + return ResponseEntity.status(e.getErrorCode().getHttpStatus()).body(ErrorResponse.from(e.getErrorCode())); + } } diff --git a/src/main/java/hyundai/softeer/orange/config/AppConfig.java b/src/main/java/hyundai/softeer/orange/config/AppConfig.java index 15ba4d91..92286c18 100644 --- a/src/main/java/hyundai/softeer/orange/config/AppConfig.java +++ b/src/main/java/hyundai/softeer/orange/config/AppConfig.java @@ -1,6 +1,7 @@ package hyundai.softeer.orange.config; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -12,6 +13,8 @@ public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // LocalDateTime파싱이 목적 objectMapper.registerModule(new JavaTimeModule()); + // timestamp를 문자열로 전달 + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return objectMapper; } } diff --git a/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapper.java b/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapper.java index 913b8b3c..eef5742e 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapper.java +++ b/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapper.java @@ -7,24 +7,34 @@ import hyundai.softeer.orange.event.draw.entity.DrawEvent; import hyundai.softeer.orange.event.draw.entity.DrawEventMetadata; import hyundai.softeer.orange.event.draw.entity.DrawEventScorePolicy; +import hyundai.softeer.orange.event.draw.repository.DrawEventMetadataRepository; +import hyundai.softeer.orange.event.draw.repository.DrawEventScorePolicyRepository; import hyundai.softeer.orange.event.dto.EventDto; import hyundai.softeer.orange.event.dto.draw.DrawEventDto; +import hyundai.softeer.orange.event.dto.draw.DrawEventMetadataDto; +import hyundai.softeer.orange.event.dto.draw.DrawEventScorePolicyDto; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * EventMetadata에 DrawEvent를 주입해주는 매퍼 */ +@RequiredArgsConstructor @Component public class DrawEventFieldMapper implements EventFieldMapper { + private final DrawEventMetadataRepository deMetadataRepository; + private final DrawEventScorePolicyRepository deScorePolicyRepository; + @Override public boolean canHandle(EventType eventType) { return eventType.equals(EventType.draw); } @Override - public void handle(EventMetadata metadata, EventDto eventDto) { + public void fetchToEventEntity(EventMetadata metadata, EventDto eventDto) { DrawEventDto dto = eventDto.getDraw(); // 비어 있으면 안됨. if (dto == null) throw new EventException(ErrorCode.INVALID_JSON); @@ -52,4 +62,127 @@ public void handle(EventMetadata metadata, EventDto eventDto) { ).toList(); event.setMetadataList(metadataList); } + + @Override + public void fetchToDto(EventMetadata metadata, EventDto eventDto) { + Optional drawEventOpt = metadata.getDrawEventList().stream().findFirst(); + // drawEvent 정보가 있으면 넣기 + drawEventOpt.ifPresent(drawEvent -> { + DrawEventDto drawEventDto = DrawEventDto + .builder() + .id(drawEvent.getId()) + .metadata(drawEvent.getMetadataList().stream().map( + it -> DrawEventMetadataDto.builder() + .id(it.getId()) + .count(it.getCount()) + .grade(it.getGrade()) + .prizeInfo(it.getPrizeInfo()) + .build() + ).toList()) + .policies(drawEvent.getPolicyList().stream().map( + it -> DrawEventScorePolicyDto.builder() + .id(it.getId()) + .score(it.getScore()) + .action(it.getAction()) + .build() + ).toList()) + .build(); + + eventDto.setDraw(drawEventDto); + }); + } + + @Override + public void editEventField(EventMetadata metadata, EventDto dto) { + Optional drawEventOpt = metadata.getDrawEventList().stream().findFirst(); + DrawEvent drawEvent = drawEventOpt.orElseThrow(() -> new EventException(ErrorCode.EVENT_NOT_FOUND)); + DrawEventDto drawEventDto = dto.getDraw(); + + editDrawEventMetadata(drawEvent, drawEventDto); + editDrawEventScorePolicy(drawEvent, drawEventDto); + } + + // 나중에 가능하다면 리팩토링 방법 찾아보자. => set 기반 공통 로직 추출 + private void editDrawEventMetadata(DrawEvent drawEvent, DrawEventDto drawEventDto) { + List deMetadata = drawEvent.getMetadataList(); + + Map> deMetadataDtos = drawEventDto.getMetadata().stream() + .collect(Collectors.partitioningBy(it -> it.getId() == null, Collectors.toMap(DrawEventMetadataDto::getId, it-> it))); + // true이면 created / false이면 updated + Map createdDtos = deMetadataDtos.get(true); + Map updatedDtos = deMetadataDtos.get(false); + + Set updated = new HashSet<>(updatedDtos.keySet()); + Set deleted = deMetadata.stream().map(DrawEventMetadata::getId).collect(Collectors.toSet()); + // null은 created + updated.retainAll(deleted); // dto & entity 교집합 => updated + deleted.removeAll(updated); // entity에는 있는데 dto에는 없음 => deleted + + for(DrawEventMetadata metadata : deMetadata) { + // update에 있는 경우 + if(updated.contains(metadata.getId())) { + DrawEventMetadataDto dto = updatedDtos.get(metadata.getId()); + metadata.updateCount(dto.getCount()); + metadata.updateGrade(dto.getGrade()); + metadata.updatePrizeInfo(dto.getPrizeInfo()); + } + // delete에 있는 경우 + else if(deleted.contains(metadata.getId())) { + deMetadataRepository.delete(metadata); + } + } + deMetadata.removeIf(it -> deleted.contains(it.getId())); + + // 객체 생성 처리 + for(DrawEventMetadataDto createdDto : createdDtos.values()) { + DrawEventMetadata drawEventMetadata = DrawEventMetadata.of( + createdDto.getGrade(), + createdDto.getCount(), + createdDto.getPrizeInfo(), + drawEvent + ); + deMetadata.add(drawEventMetadata); + } + } + + private void editDrawEventScorePolicy(DrawEvent drawEvent, DrawEventDto drawEventDto) { + List policies = drawEvent.getPolicyList(); + + Map> deMetadataDtos = drawEventDto.getPolicies().stream() + .collect(Collectors.partitioningBy(it -> it.getId() == null, Collectors.toMap(DrawEventScorePolicyDto::getId, it-> it))); + // true이면 created / false이면 updated + Map createdDtos = deMetadataDtos.get(true); + Map updatedDtos = deMetadataDtos.get(false); + + Set updated = new HashSet<>(updatedDtos.keySet()); + Set deleted = policies.stream().map(DrawEventScorePolicy::getId).collect(Collectors.toSet()); + // null은 created + updated.retainAll(deleted); // dto & entity 교집합 => updated + deleted.removeAll(updated); // entity에는 있는데 dto에는 없음 => deleted + + for(DrawEventScorePolicy policy : policies) { + // update에 있는 경우 + if(updated.contains(policy.getId())) { + DrawEventScorePolicyDto dto = updatedDtos.get(policy.getId()); + policy.updateAction(dto.getAction()); + policy.updateScore(dto.getScore()); + } + // delete에 있는 경우 + else if(deleted.contains(policy.getId())) { + deScorePolicyRepository.delete(policy); + } + } + policies.removeIf(it -> deleted.contains(it.getId())); + + // 객체 생성 처리 + for(DrawEventScorePolicyDto createdDto : createdDtos.values()) { + DrawEventScorePolicy policy = DrawEventScorePolicy.of( + createdDto.getAction(), + createdDto.getScore(), + drawEvent + ); + policies.add(policy); + } + } + } diff --git a/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/EventFieldMapper.java b/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/EventFieldMapper.java index 6027aaf0..04a36e8d 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/EventFieldMapper.java +++ b/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/EventFieldMapper.java @@ -6,5 +6,7 @@ public interface EventFieldMapper { boolean canHandle(EventType eventType); - void handle(EventMetadata metadata, EventDto dto); + void fetchToEventEntity(EventMetadata metadata, EventDto dto); + void fetchToDto(EventMetadata metadata, EventDto dto); + void editEventField(EventMetadata metadata, EventDto dto); } diff --git a/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapper.java b/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapper.java index fcc3b0c8..d38c812e 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapper.java +++ b/src/main/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapper.java @@ -7,22 +7,27 @@ import hyundai.softeer.orange.event.dto.EventDto; import hyundai.softeer.orange.event.dto.fcfs.FcfsEventDto; import hyundai.softeer.orange.event.fcfs.entity.FcfsEvent; +import hyundai.softeer.orange.event.fcfs.repository.FcfsEventRepository; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * EventMetadata에 FcfsEvent를 주입해주는 매퍼 */ +@RequiredArgsConstructor @Component public class FcfsEventFieldMapper implements EventFieldMapper { + private final FcfsEventRepository fcfsEventRepository; @Override public boolean canHandle(EventType eventType) { return eventType.equals(EventType.fcfs); } @Override - public void handle(EventMetadata metadata, EventDto eventDto) { + public void fetchToEventEntity(EventMetadata metadata, EventDto eventDto) { List fcfsDtos = eventDto.getFcfs(); // 비어 있으면 안됨 if (fcfsDtos == null || fcfsDtos.isEmpty()) throw new EventException(ErrorCode.INVALID_JSON); @@ -39,4 +44,63 @@ public void handle(EventMetadata metadata, EventDto eventDto) { metadata.addFcfsEvents(fcfsEventList); } + + @Override + public void fetchToDto(EventMetadata metadata, EventDto eventDto) { + List fcfsEvents = metadata.getFcfsEventList(); + List fcfsEventDtos = fcfsEvents.stream().map(it -> FcfsEventDto + .builder() + .id(it.getId()) + .startTime(it.getStartTime()) + .endTime(it.getEndTime()) + .participantCount(it.getParticipantCount()) + .prizeInfo(it.getPrizeInfo()) + .build() + ).toList(); + eventDto.setFcfsList(fcfsEventDtos); + } + + @Override + public void editEventField(EventMetadata metadata, EventDto eventDto) { + List fcfsEvents = metadata.getFcfsEventList(); + // 집합을 이용해서 created / updated / deleted 를 구분 + Map> fcfsAllDtos = eventDto.getFcfs().stream() + .collect(Collectors.partitioningBy(it -> it.getId() == null, Collectors.toMap(FcfsEventDto::getId, it-> it))); + // true이면 created / false이면 updated + Map createdDtos = fcfsAllDtos.get(true); + Map updatedDtos = fcfsAllDtos.get(false); + + Set updated = new HashSet<>(updatedDtos.keySet()); + Set deleted = fcfsEvents.stream().map(FcfsEvent::getId).collect(Collectors.toSet()); + // null은 created + updated.retainAll(deleted); // dto & entity 교집합 => updated + deleted.removeAll(updated); // entity에는 있는데 dto에는 없음 => deleted + for(FcfsEvent event: fcfsEvents) { + // update에 있는 경우 + if(updated.contains(event.getId())) { + FcfsEventDto updatedDto = updatedDtos.get(event.getId()); + event.updateStartTime(updatedDto.getStartTime()); + event.updateEndTime(updatedDto.getEndTime()); + event.updateParticipantCount(updatedDto.getParticipantCount()); + event.updatePrizeInfo(updatedDto.getPrizeInfo()); + } + // delete에 있는 경우 + else if(deleted.contains(event.getId())) { + fcfsEventRepository.delete(event); + } + } + fcfsEvents.removeIf(it -> deleted.contains(it.getId())); + + // 객체 생성 처리 + for(FcfsEventDto createdDto : createdDtos.values()) { + FcfsEvent newEvent = FcfsEvent.of( + createdDto.getStartTime(), + createdDto.getEndTime(), + createdDto.getParticipantCount(), + createdDto.getPrizeInfo(), + metadata + ); + fcfsEvents.add(newEvent); + } + } } diff --git a/src/main/java/hyundai/softeer/orange/event/common/controller/EventController.java b/src/main/java/hyundai/softeer/orange/event/common/controller/EventController.java index 2eeb56ab..87cffaa4 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/controller/EventController.java +++ b/src/main/java/hyundai/softeer/orange/event/common/controller/EventController.java @@ -5,9 +5,9 @@ import hyundai.softeer.orange.event.common.service.EventService; import hyundai.softeer.orange.event.dto.EventDto; import hyundai.softeer.orange.event.dto.EventFrameCreateRequest; +import hyundai.softeer.orange.event.dto.group.EventEditGroup; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -21,7 +21,7 @@ */ @Slf4j @RequiredArgsConstructor -@RequestMapping("/event") +@RequestMapping("/api/v1/event") @RestController public class EventController { private final EventService eventService; @@ -37,6 +37,34 @@ public ResponseEntity createEvent(@Validated @RequestBody EventDto eventDto) return ResponseEntity.status(HttpStatus.CREATED).build(); } + @Auth({AuthRole.admin}) + @GetMapping("/edit") + @Operation(summary = "이벤트 수정 초기 데이터 획득", description = "이벤트 정보 수정을 위해 초기 정보를 받는다", responses = { + @ApiResponse(responseCode = "200", description = "이벤트 정보를 정상적으로 받음"), + @ApiResponse(responseCode = "404", description = "대응되는 이벤트가 존재하지 않음") + }) + public ResponseEntity getEventEditData( + @RequestParam("eventId") String eventId + ) { + EventDto eventInfo = eventService.getEventInfo(eventId); + return ResponseEntity.ok(eventInfo); + } + + @Auth({AuthRole.admin}) + @PostMapping("/edit") + @Operation(summary = "이벤트 수정", description = "관리자가 이벤트를 수정한다", responses = { + @ApiResponse(responseCode = "200", description = "이벤트 생성 성공"), + @ApiResponse(responseCode = "4xx", description = "유저 측 실수로 이벤트 생성 실패") + }) + public ResponseEntity editEvent( + @Validated({EventEditGroup.class}) @RequestBody EventDto eventDto + ) { + eventService.editEvent(eventDto); + return ResponseEntity.ok().build(); + } + + + @Auth({AuthRole.admin}) @PostMapping("/frame") @Operation(summary = "이벤트 프레임 생성", description = "관리자가 이벤트 프레임을 새롭게 등록한다", responses = { @@ -47,4 +75,6 @@ public ResponseEntity createEventFrame(@Valid @RequestBody EventFrameCreateRe eventService.createEventFrame(req.getName()); return ResponseEntity.status(HttpStatus.CREATED).build(); } + + } diff --git a/src/main/java/hyundai/softeer/orange/event/common/entity/EventMetadata.java b/src/main/java/hyundai/softeer/orange/event/common/entity/EventMetadata.java index 297b6a65..62430df5 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/entity/EventMetadata.java +++ b/src/main/java/hyundai/softeer/orange/event/common/entity/EventMetadata.java @@ -49,18 +49,38 @@ public class EventMetadata { @Column private EventStatus status; + public void updateName(String name) { + this.name = name; + } + + public void updateDescription(String description) { + this.description = description; + } + + public void updateStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public void updateEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public void updateUrl(String url) { + this.url = url; + } + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="event_frame_id") private EventFrame eventFrame; - @OneToMany(mappedBy = "eventMetadata", cascade = {CascadeType.PERSIST}) + @OneToMany(mappedBy = "eventMetadata", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) private final List drawEventList = new ArrayList<>(); public void addDrawEvent(DrawEvent drawEvent) { this.drawEventList.add(drawEvent); } - @OneToMany(mappedBy = "eventMetaData", cascade = {CascadeType.PERSIST}) + @OneToMany(mappedBy = "eventMetaData", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) private final List fcfsEventList = new ArrayList<>(); public void addFcfsEvents(List fcfsEventList) { diff --git a/src/main/java/hyundai/softeer/orange/event/common/repository/EventMetadataRepository.java b/src/main/java/hyundai/softeer/orange/event/common/repository/EventMetadataRepository.java index c8c6a884..ff2f50cc 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/repository/EventMetadataRepository.java +++ b/src/main/java/hyundai/softeer/orange/event/common/repository/EventMetadataRepository.java @@ -4,6 +4,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface EventMetadataRepository extends JpaRepository { + Optional findFirstByEventId(String eventId); } diff --git a/src/main/java/hyundai/softeer/orange/event/common/service/EventService.java b/src/main/java/hyundai/softeer/orange/event/common/service/EventService.java index 5ee07468..d386a28d 100644 --- a/src/main/java/hyundai/softeer/orange/event/common/service/EventService.java +++ b/src/main/java/hyundai/softeer/orange/event/common/service/EventService.java @@ -12,12 +12,11 @@ import hyundai.softeer.orange.event.common.repository.EventMetadataRepository; import hyundai.softeer.orange.event.component.EventKeyGenerator; import hyundai.softeer.orange.event.dto.EventDto; -import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; -import java.util.Map; import java.util.Optional; /** @@ -36,9 +35,9 @@ public class EventService { public void createEvent(EventDto eventDto) { // 1. eventframe을 찾는다. 없으면 작업이 의미 X Optional frameOpt = efRepository.findByName(eventDto.getTag()); - if (frameOpt.isEmpty()) throw new EventException(ErrorCode.EVENT_FRAME_NOT_FOUND); + EventFrame frame = frameOpt + .orElseThrow(() -> new EventException(ErrorCode.EVENT_FRAME_NOT_FOUND)); - EventFrame frame = frameOpt.get(); String eventKey = keyGenerator.generate(); // 2. 이벤트 메타데이터 객체를 생성한다. @@ -56,16 +55,60 @@ public void createEvent(EventDto eventDto) { EventType type = eventDto.getEventType(); EventFieldMapper mapper = mapperMatcher.getMapper(type); + if(mapper == null) throw new EventException(ErrorCode.INVALID_EVENT_TYPE); + + mapper.fetchToEventEntity(eventMetadata, eventDto); + + emRepository.save(eventMetadata); + } + + @Transactional + public void editEvent(EventDto eventDto) { + String eventId = eventDto.getEventId(); + Optional metadataOpt = emRepository.findFirstByEventId(eventId); + EventMetadata eventMetadata = metadataOpt + .orElseThrow(() -> new EventException(ErrorCode.EVENT_NOT_FOUND)); + eventMetadata.updateName(eventDto.getName()); + eventMetadata.updateDescription(eventDto.getDescription()); + eventMetadata.updateStartTime(eventDto.getStartTime()); + eventMetadata.updateEndTime(eventDto.getEndTime()); + eventMetadata.updateUrl(eventDto.getUrl()); + EventFieldMapper mapper = mapperMatcher.getMapper(eventDto.getEventType()); if(mapper == null) throw new EventException(ErrorCode.INVALID_EVENT_TYPE); - mapper.handle(eventMetadata, eventDto); + mapper.editEventField(eventMetadata, eventDto); emRepository.save(eventMetadata); } + @Transactional(readOnly = true) + public EventDto getEventInfo(String eventId) { + Optional metadataOpt = emRepository.findFirstByEventId(eventId); + EventMetadata metadata = metadataOpt + .orElseThrow(() -> new EventException(ErrorCode.EVENT_NOT_FOUND)); + + EventFieldMapper mapper = mapperMatcher.getMapper(metadata.getEventType()); + if(mapper == null) throw new EventException(ErrorCode.INVALID_EVENT_TYPE); + + EventDto eventDto = EventDto.builder() + .id(metadata.getId()) + .eventId(metadata.getEventId()) + .name(metadata.getName()) + .description(metadata.getDescription()) + .url(metadata.getUrl()) + .startTime(metadata.getStartTime()) + .endTime(metadata.getEndTime()) + .eventType(metadata.getEventType()) + .build(); + + mapper.fetchToDto(metadata, eventDto); + return eventDto; + } + @Transactional public void createEventFrame(String name) { EventFrame eventFrame = EventFrame.of(name); efRepository.save(eventFrame); } + } diff --git a/src/main/java/hyundai/softeer/orange/event/component/EventKeyGenerator.java b/src/main/java/hyundai/softeer/orange/event/component/EventKeyGenerator.java index 31e50452..367e40be 100644 --- a/src/main/java/hyundai/softeer/orange/event/component/EventKeyGenerator.java +++ b/src/main/java/hyundai/softeer/orange/event/component/EventKeyGenerator.java @@ -25,7 +25,7 @@ public String generate() { public String generate(LocalDateTime now) { LocalDateTime nextDay = now.plusDays(1).toLocalDate().atTime(0,0,5); - String dateInfo = formatter.format(LocalDateTime.now()); + String dateInfo = formatter.format(now); String incKey = EventConst.REDIS_KEY_PREFIX + dateInfo; Long number = redisTemplate.opsForValue().increment(incKey); diff --git a/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEvent.java b/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEvent.java index f7ab1021..d94753e5 100644 --- a/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEvent.java +++ b/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEvent.java @@ -22,10 +22,14 @@ public class DrawEvent { @JoinColumn(name="event_metadata_id") private EventMetadata eventMetadata; - @OneToMany(mappedBy ="drawEvent", cascade = {CascadeType.PERSIST}) + @OneToMany(mappedBy ="drawEvent", + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + fetch = FetchType.EAGER) // 추첨 이벤트는 항상 policy와 함께 사용되므로 EAGER로 설정 private List policyList = new ArrayList<>(); - @OneToMany(mappedBy ="drawEvent", cascade = {CascadeType.PERSIST}) + @OneToMany(mappedBy ="drawEvent", + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + fetch = FetchType.EAGER) // 추첨 이벤트는 항상 metadata와 함께 사용되므로 EAGER로 설정 private List metadataList = new ArrayList<>(); @OneToMany(mappedBy ="drawEvent") diff --git a/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventMetadata.java b/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventMetadata.java index dc055614..cfb978cb 100644 --- a/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventMetadata.java +++ b/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventMetadata.java @@ -23,6 +23,18 @@ public class DrawEventMetadata { @JoinColumn(name = "draw_event_id") private DrawEvent drawEvent; + public void updateGrade(Long grade) { + this.grade = grade; + } + + public void updateCount(Long count) { + this.count = count; + } + + public void updatePrizeInfo(String prizeInfo) { + this.prizeInfo = prizeInfo; + } + public static DrawEventMetadata of(Long grade, Long count, String prizeInfo, DrawEvent drawEvent) { DrawEventMetadata metadata = new DrawEventMetadata(); metadata.grade = grade; diff --git a/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventScorePolicy.java b/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventScorePolicy.java index 69d9fbe3..b0ba2b08 100644 --- a/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventScorePolicy.java +++ b/src/main/java/hyundai/softeer/orange/event/draw/entity/DrawEventScorePolicy.java @@ -14,7 +14,6 @@ public class DrawEventScorePolicy { @Column private DrawEventAction action; - @Column private Integer score; @@ -22,6 +21,14 @@ public class DrawEventScorePolicy { @JoinColumn(name = "draw_event_id") private DrawEvent drawEvent; + public void updateAction(DrawEventAction action) { + this.action = action; + } + + public void updateScore(Integer score) { + this.score = score; + } + public static DrawEventScorePolicy of(DrawEventAction action, Integer score, DrawEvent drawEvent) { DrawEventScorePolicy policy = new DrawEventScorePolicy(); policy.action = action; diff --git a/src/main/java/hyundai/softeer/orange/event/draw/repository/DrawEventRepository.java b/src/main/java/hyundai/softeer/orange/event/draw/repository/DrawEventRepository.java index c03c0bdd..6ba0d852 100644 --- a/src/main/java/hyundai/softeer/orange/event/draw/repository/DrawEventRepository.java +++ b/src/main/java/hyundai/softeer/orange/event/draw/repository/DrawEventRepository.java @@ -1,9 +1,11 @@ package hyundai.softeer.orange.event.draw.repository; +import hyundai.softeer.orange.event.common.entity.EventMetadata; import hyundai.softeer.orange.event.draw.entity.DrawEvent; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository -public interface DrawEventRepository extends JpaRepository { -} +public interface DrawEventRepository extends JpaRepository { } diff --git a/src/main/java/hyundai/softeer/orange/event/dto/EventDto.java b/src/main/java/hyundai/softeer/orange/event/dto/EventDto.java index 743004a8..c761b219 100644 --- a/src/main/java/hyundai/softeer/orange/event/dto/EventDto.java +++ b/src/main/java/hyundai/softeer/orange/event/dto/EventDto.java @@ -8,11 +8,17 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import java.time.LocalDateTime; import java.util.List; +@Builder +@NoArgsConstructor +@AllArgsConstructor @Getter public class EventDto { @NotNull(groups = {EventEditGroup.class}) @@ -46,4 +52,12 @@ public class EventDto { @Valid private DrawEventDto draw; + + public void setDraw(DrawEventDto drawEventDto) { + this.draw = drawEventDto; + } + + public void setFcfsList(List fcfsEventDtos) { + this.fcfs = fcfsEventDtos; + } } \ No newline at end of file diff --git a/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventDto.java b/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventDto.java index 2cf87dbe..06229f45 100644 --- a/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventDto.java +++ b/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventDto.java @@ -3,14 +3,16 @@ import hyundai.softeer.orange.event.dto.group.EventEditGroup; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; -import lombok.Getter; +import lombok.*; import java.util.List; +@Builder +@NoArgsConstructor +@AllArgsConstructor @Getter +@Setter public class DrawEventDto { - - @NotNull(groups = {EventEditGroup.class}) private Long id; @NotNull diff --git a/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventMetadataDto.java b/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventMetadataDto.java index 3aed92e6..f1fc73f0 100644 --- a/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventMetadataDto.java +++ b/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventMetadataDto.java @@ -2,11 +2,13 @@ import hyundai.softeer.orange.event.dto.group.EventEditGroup; import jakarta.validation.constraints.NotNull; -import lombok.Getter; +import lombok.*; +@Builder +@NoArgsConstructor +@AllArgsConstructor @Getter public class DrawEventMetadataDto { - @NotNull(groups = {EventEditGroup.class}) private Long id; @NotNull diff --git a/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventScorePolicyDto.java b/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventScorePolicyDto.java index 940d32c2..c800da96 100644 --- a/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventScorePolicyDto.java +++ b/src/main/java/hyundai/softeer/orange/event/dto/draw/DrawEventScorePolicyDto.java @@ -4,11 +4,13 @@ import hyundai.softeer.orange.event.dto.group.EventEditGroup; import jakarta.validation.constraints.NotNull; -import lombok.Getter; +import lombok.*; +@Builder +@NoArgsConstructor +@AllArgsConstructor @Getter public class DrawEventScorePolicyDto { - @NotNull(groups = {EventEditGroup.class}) private Long id; @NotNull diff --git a/src/main/java/hyundai/softeer/orange/event/dto/fcfs/FcfsEventDto.java b/src/main/java/hyundai/softeer/orange/event/dto/fcfs/FcfsEventDto.java index b207aa81..33696cc6 100644 --- a/src/main/java/hyundai/softeer/orange/event/dto/fcfs/FcfsEventDto.java +++ b/src/main/java/hyundai/softeer/orange/event/dto/fcfs/FcfsEventDto.java @@ -1,15 +1,20 @@ package hyundai.softeer.orange.event.dto.fcfs; -import hyundai.softeer.orange.event.dto.group.EventCreateGroup; +import hyundai.softeer.orange.event.dto.group.EventEditGroup; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +import lombok.RequiredArgsConstructor; import java.time.LocalDateTime; +@Builder +@RequiredArgsConstructor +@AllArgsConstructor @Getter public class FcfsEventDto { - @NotNull(groups = {EventCreateGroup.class}) private Long id; @NotNull @@ -23,4 +28,4 @@ public class FcfsEventDto { @NotBlank private String prizeInfo; -} +} \ No newline at end of file diff --git a/src/main/java/hyundai/softeer/orange/event/fcfs/entity/FcfsEvent.java b/src/main/java/hyundai/softeer/orange/event/fcfs/entity/FcfsEvent.java index e48d216f..2f19d96a 100644 --- a/src/main/java/hyundai/softeer/orange/event/fcfs/entity/FcfsEvent.java +++ b/src/main/java/hyundai/softeer/orange/event/fcfs/entity/FcfsEvent.java @@ -38,6 +38,22 @@ public class FcfsEvent { @JoinColumn(name = "event_metadata_id") private EventMetadata eventMetaData; + public void updateStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public void updateEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public void updateParticipantCount(Long participantCount) { + this.participantCount = participantCount; + } + + public void updatePrizeInfo(String prizeInfo) { + this.prizeInfo = prizeInfo; + } + @OneToMany(mappedBy = "fcfsEvent") private final List infos = new ArrayList<>(); diff --git a/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/EventFieldMapperMatcherTest.java b/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/EventFieldMapperMatcherTest.java index 81737d8d..629a2e00 100644 --- a/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/EventFieldMapperMatcherTest.java +++ b/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/EventFieldMapperMatcherTest.java @@ -3,12 +3,15 @@ import hyundai.softeer.orange.event.common.component.eventFieldMapper.mapper.DrawEventFieldMapper; import hyundai.softeer.orange.event.common.component.eventFieldMapper.mapper.EventFieldMapper; import hyundai.softeer.orange.event.common.enums.EventType; +import hyundai.softeer.orange.event.draw.repository.DrawEventMetadataRepository; +import hyundai.softeer.orange.event.draw.repository.DrawEventScorePolicyRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class EventFieldMapperMatcherTest { @DisplayName("이벤트 타입에 대응되는 매퍼가 있다면 반환한다. 없다면 null을 반환한다.") @@ -16,7 +19,10 @@ class EventFieldMapperMatcherTest { void returnMapperIfExistElseNull() { EventType existType = EventType.draw; EventType notExistType = EventType.fcfs; - List mappers = List.of(new DrawEventFieldMapper()); + DrawEventMetadataRepository repo1 = mock(DrawEventMetadataRepository.class); + DrawEventScorePolicyRepository repo2 = mock(DrawEventScorePolicyRepository.class); + + List mappers = List.of(new DrawEventFieldMapper(repo1, repo2)); EventFieldMapperMatcher mapperMatcher = new EventFieldMapperMatcher(mappers); var mapper1 = mapperMatcher.getMapper(existType); diff --git a/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapperTest.java b/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapperTest.java index 21ac2c18..a5d5a5f1 100644 --- a/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapperTest.java +++ b/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/DrawEventFieldMapperTest.java @@ -2,13 +2,18 @@ import hyundai.softeer.orange.event.common.entity.EventMetadata; import hyundai.softeer.orange.event.common.enums.EventType; -import hyundai.softeer.orange.event.draw.entity.DrawEvent; +import hyundai.softeer.orange.event.draw.repository.DrawEventMetadataRepository; +import hyundai.softeer.orange.event.draw.repository.DrawEventScorePolicyRepository; import hyundai.softeer.orange.event.dto.EventDto; import hyundai.softeer.orange.event.dto.draw.DrawEventDto; import hyundai.softeer.orange.event.dto.draw.DrawEventMetadataDto; import hyundai.softeer.orange.event.dto.draw.DrawEventScorePolicyDto; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.TestPropertySource; import java.util.List; @@ -17,8 +22,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@DataJpaTest +@TestPropertySource(locations = "classpath:application-test.yml") class DrawEventFieldMapperTest { - DrawEventFieldMapper mapper = new DrawEventFieldMapper(); + @Autowired + DrawEventMetadataRepository drawEventMetadataRepository; + @Autowired + DrawEventScorePolicyRepository drawEventScorePolicyRepository; + DrawEventFieldMapper mapper; + + @BeforeEach + void setUp() { + mapper = new DrawEventFieldMapper(drawEventMetadataRepository, drawEventScorePolicyRepository); + } + @DisplayName("canHandle은 해당 타입을 지원하는지 여부를 반환한다.") @Test @@ -32,19 +49,19 @@ void canHandle_returnTypeSupported() { @DisplayName("EventDto에 draw 필드가 없으면 예외가 터진다.") @Test - void throwErrorIfFcfsDtoNotExists() { + void fetchToEventEntity_throwErrorIfFcfsDtoNotExists() { EventMetadata metadata = new EventMetadata(); EventDto dto1 = new EventDto(); // drawDto 없음 assertThatThrownBy(() -> { - mapper.handle(metadata, dto1); + mapper.fetchToEventEntity(metadata, dto1); }); } @DisplayName("정상적인 EventDto가 들어오면 정상적으로 관계를 설정한다.") @Test - void setRelationIfEventDtoIsValid() { + void fetchToEventEntity_setRelationIfEventDtoIsValid() { EventMetadata metadata = new EventMetadata(); EventDto dto = mock(EventDto.class); DrawEventDto drawEventDto = mock(DrawEventDto.class); @@ -52,7 +69,7 @@ void setRelationIfEventDtoIsValid() { when(drawEventDto.getMetadata()).thenReturn(List.of(new DrawEventMetadataDto())); when(drawEventDto.getPolicies()).thenReturn(List.of(new DrawEventScorePolicyDto())); - mapper.handle(metadata, dto); + mapper.fetchToEventEntity(metadata, dto); var drawEvents = metadata.getDrawEventList(); var drawEvent = drawEvents.get(0); @@ -68,4 +85,23 @@ void setRelationIfEventDtoIsValid() { assertThat(oneDrawMetadata.getDrawEvent()).isSameAs(drawEvent); assertThat(oneEventPolicy.getDrawEvent()).isSameAs(drawEvent); } + + @DisplayName("draw 이벤트가 없으면 예외가 발생한다.") + @Test + void editEventField_throwIfDrawEventNotExists() { + EventMetadata metadata = new EventMetadata(); + EventDto dto = mock(EventDto.class); + assertThatThrownBy(() -> { + mapper.editEventField(metadata, dto); + }); + } + + // TODO: repository 통합 테스트 코드 작성 +// @DisplayName("규칙에 따라 정상적으로 DrawEvent를 갱신해야 한다.") +// @Test +// void editEventField_testOpIsValid() { +// // 1. DrawEvent +// EventMetadata metadata = new EventMetadata(); +// EventDto dto = new EventDto(); +// } } \ No newline at end of file diff --git a/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapperTest.java b/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapperTest.java index f1150d97..71bf8a9a 100644 --- a/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapperTest.java +++ b/src/test/java/hyundai/softeer/orange/event/common/component/eventFieldMapper/mapper/FcfsEventFieldMapperTest.java @@ -5,20 +5,25 @@ import hyundai.softeer.orange.event.dto.EventDto; import hyundai.softeer.orange.event.dto.fcfs.FcfsEventDto; import hyundai.softeer.orange.event.fcfs.entity.FcfsEvent; -import org.assertj.core.api.Assertions; +import hyundai.softeer.orange.event.fcfs.repository.FcfsEventRepository; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class FcfsEventFieldMapperTest { - FcfsEventFieldMapper mapper = new FcfsEventFieldMapper(); + + FcfsEventFieldMapper mapper; + @BeforeEach + void setUp() { + FcfsEventRepository repo = mock(FcfsEventRepository.class); + mapper = new FcfsEventFieldMapper(repo); + } @DisplayName("canHandle은 해당 타입을 지원하는지 여부를 반환한다.") @Test @@ -39,11 +44,11 @@ void throwErrorIfFcfsDtoNotExists() { when(dto2.getFcfs()).thenReturn(List.of()); assertThatThrownBy(() -> { - mapper.handle(metadata, dto1); + mapper.fetchToEventEntity(metadata, dto1); }); assertThatThrownBy(() -> { - mapper.handle(metadata, dto2); + mapper.fetchToEventEntity(metadata, dto2); }); } @@ -58,7 +63,7 @@ void setRelationIfFcfsDtoExists() { ); when(dto.getFcfs()).thenReturn(dtos); - mapper.handle(metadata, dto); + mapper.fetchToEventEntity(metadata, dto); List fcfsEvents = metadata.getFcfsEventList(); diff --git a/src/test/java/hyundai/softeer/orange/event/common/service/EventServiceTest.java b/src/test/java/hyundai/softeer/orange/event/common/service/EventServiceTest.java index 0d43b693..055e8cd4 100644 --- a/src/test/java/hyundai/softeer/orange/event/common/service/EventServiceTest.java +++ b/src/test/java/hyundai/softeer/orange/event/common/service/EventServiceTest.java @@ -2,7 +2,6 @@ import hyundai.softeer.orange.common.ErrorCode; import hyundai.softeer.orange.event.common.component.eventFieldMapper.EventFieldMapperMatcher; -import hyundai.softeer.orange.event.common.component.eventFieldMapper.mapper.EventFieldMapper; import hyundai.softeer.orange.event.common.component.eventFieldMapper.mapper.FcfsEventFieldMapper; import hyundai.softeer.orange.event.common.entity.EventFrame; import hyundai.softeer.orange.event.common.entity.EventMetadata; @@ -12,17 +11,14 @@ import hyundai.softeer.orange.event.common.repository.EventMetadataRepository; import hyundai.softeer.orange.event.component.EventKeyGenerator; import hyundai.softeer.orange.event.dto.EventDto; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @@ -46,7 +42,7 @@ void setUp() { @DisplayName("대응되는 eventframe이 없으면 예외 반환") @Test void createEvent_throwErrorIFNoMatchedEventFrame() { - EventDto eventDto = new EventDto(); + EventDto eventDto = EventDto.builder().build(); assertThatThrownBy(() -> { eventService.createEvent(eventDto);