diff --git a/src/main/java/life/mosu/mosuserver/application/admin/AdminBannerService.java b/src/main/java/life/mosu/mosuserver/application/admin/AdminBannerService.java index 36b0d5ec..f57d25ff 100644 --- a/src/main/java/life/mosu/mosuserver/application/admin/AdminBannerService.java +++ b/src/main/java/life/mosu/mosuserver/application/admin/AdminBannerService.java @@ -7,6 +7,7 @@ import life.mosu.mosuserver.global.exception.ErrorCode; import life.mosu.mosuserver.infra.persistence.s3.S3Service; import life.mosu.mosuserver.presentation.admin.dto.BannerInfoResponse; +import life.mosu.mosuserver.presentation.admin.dto.BannerInfoResponse.AttachmentResponse; import life.mosu.mosuserver.presentation.admin.dto.BannerRequest; import life.mosu.mosuserver.presentation.admin.dto.BannerResponse; import lombok.RequiredArgsConstructor; @@ -29,9 +30,15 @@ public List getAll() { public BannerInfoResponse getByBannerId(Long bannerId) { BannerJpaEntity banner = bannerJpaRepository.findById(bannerId) .orElseThrow(() -> new CustomRuntimeException(ErrorCode.BANNER_NOT_FOUND)); - String imgUrl = s3Service.getPublicUrl(banner.getS3Key()); + + String url = null; + if (banner.getS3Key() != null) { + url = s3Service.getPublicUrl(banner.getS3Key()); + } + + AttachmentResponse attachment = AttachmentResponse.of(banner.getFileName(), url); return BannerInfoResponse.of(banner.getTitle(), banner.getDeadline(), banner.getLink(), - imgUrl); + attachment); } @Transactional diff --git a/src/main/java/life/mosu/mosuserver/application/event/EventAttachmentService.java b/src/main/java/life/mosu/mosuserver/application/event/EventAttachmentService.java index 1f4d278d..f6b4025a 100644 --- a/src/main/java/life/mosu/mosuserver/application/event/EventAttachmentService.java +++ b/src/main/java/life/mosu/mosuserver/application/event/EventAttachmentService.java @@ -1,40 +1,40 @@ -package life.mosu.mosuserver.application.event; - -import java.util.List; -import life.mosu.mosuserver.domain.event.EventAttachmentRepository; -import life.mosu.mosuserver.domain.event.EventJpaEntity; -import life.mosu.mosuserver.infra.persistence.s3.AttachmentService; -import life.mosu.mosuserver.infra.persistence.s3.FileUploadHelper; -import life.mosu.mosuserver.presentation.common.FileRequest; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class EventAttachmentService implements AttachmentService { - - private final EventAttachmentRepository eventAttachmentRepository; - private final FileUploadHelper fileUploadHelper; - - @Override - public void createAttachment(List request, EventJpaEntity eventEntity) { - if (request == null || request.isEmpty()) { - return; - } - fileUploadHelper.saveAttachments( - request, - eventEntity.getId(), - eventAttachmentRepository, - (fileRequest, eventId) -> fileRequest.toEventAttachmentEntity(eventEntity.getId()), - FileRequest::s3Key - ); - } - - @Override - public void deleteAttachment(EventJpaEntity entity) { - if (eventAttachmentRepository.findByEventId(entity.getId()).isPresent()) { - eventAttachmentRepository.deleteByEventId(entity.getId()); - } - } - -} +//package life.mosu.mosuserver.application.event; +// +//import java.util.List; +//import life.mosu.mosuserver.domain.event.EventAttachmentRepository; +//import life.mosu.mosuserver.domain.event.EventJpaEntity; +//import life.mosu.mosuserver.infra.persistence.s3.AttachmentService; +//import life.mosu.mosuserver.infra.persistence.s3.FileUploadHelper; +//import life.mosu.mosuserver.presentation.common.FileRequest; +//import lombok.RequiredArgsConstructor; +//import org.springframework.stereotype.Service; +// +//@Service +//@RequiredArgsConstructor +//public class EventAttachmentService implements AttachmentService { +// +// private final EventAttachmentRepository eventAttachmentRepository; +// private final FileUploadHelper fileUploadHelper; +// +// @Override +// public void createAttachment(List request, EventJpaEntity eventEntity) { +// if (request == null || request.isEmpty()) { +// return; +// } +// fileUploadHelper.saveAttachments( +// request, +// eventEntity.getId(), +// eventAttachmentRepository, +// (fileRequest, eventId) -> fileRequest.toEventAttachmentEntity(eventEntity.getId()), +// FileRequest::s3Key +// ); +// } +// +// @Override +// public void deleteAttachment(EventJpaEntity entity) { +// if (eventAttachmentRepository.findByEventId(entity.getId()).isPresent()) { +// eventAttachmentRepository.deleteByEventId(entity.getId()); +// } +// } +// +//} diff --git a/src/main/java/life/mosu/mosuserver/application/event/EventService.java b/src/main/java/life/mosu/mosuserver/application/event/EventService.java index 86c74ced..0c80eec1 100644 --- a/src/main/java/life/mosu/mosuserver/application/event/EventService.java +++ b/src/main/java/life/mosu/mosuserver/application/event/EventService.java @@ -3,13 +3,15 @@ import java.util.List; import life.mosu.mosuserver.domain.event.EventJpaEntity; import life.mosu.mosuserver.domain.event.EventJpaRepository; -import life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection; +import life.mosu.mosuserver.domain.event.EventQueryRepository; import life.mosu.mosuserver.global.exception.CustomRuntimeException; import life.mosu.mosuserver.global.exception.ErrorCode; +import life.mosu.mosuserver.global.support.CursorResponse; import life.mosu.mosuserver.infra.persistence.s3.S3Service; import life.mosu.mosuserver.presentation.event.dto.EventRequest; import life.mosu.mosuserver.presentation.event.dto.EventResponse; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -19,37 +21,48 @@ public class EventService { private final EventJpaRepository eventJpaRepository; - private final EventAttachmentService attachmentService; + private final EventQueryRepository eventQueryRepository; + // private final EventAttachmentService attachmentService; private final S3Service s3Service; @Transactional public void createEvent(EventRequest request) { EventJpaEntity eventEntity = eventJpaRepository.save(request.toEntity()); - attachmentService.createAttachment(request.optionalAttachment(), eventEntity); +// attachmentService.createAttachment(request.optionalAttachment(), eventEntity); } @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) - public List getEvents() { - List events = eventJpaRepository.findAllWithAttachment(); + public CursorResponse getEvents(Long cursorId) { + Slice eventSlice = eventQueryRepository.findAllByCursorId(cursorId); - return events.stream() + List events = eventSlice.getContent().stream() .map(event -> { - String url = event.attachment().s3Key() != null ? s3Service.getPublicUrl( - event.attachment().s3Key()) : null; + String url = event.getS3Key() != null ? s3Service.getPublicUrl( + event.getS3Key()) : null; return EventResponse.of(event, url); }) .toList(); + + Long nextCursor = eventSlice.hasNext() + ? eventSlice.getContent().getLast().getId() + : null; + + return CursorResponse.of( + events, + eventSlice.isLast(), + eventSlice.getNumberOfElements(), + nextCursor); } @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) public EventResponse getEventDetail(Long eventId) { - EventWithAttachmentProjection eventEntity = eventJpaRepository.findWithAttachmentById( + EventJpaEntity eventEntity = eventJpaRepository.findById( eventId) .orElseThrow(() -> new CustomRuntimeException(ErrorCode.EVENT_NOT_FOUND)); - String eventUrl = eventEntity.attachment().s3Key() != null ? s3Service.getPublicUrl( - eventEntity.attachment().s3Key()) : null; + String eventUrl = eventEntity.getS3Key() != null ? s3Service.getPublicUrl( + eventEntity.getS3Key()) : null; return EventResponse.of(eventEntity, eventUrl); } @@ -59,12 +72,16 @@ public void update(EventRequest request, Long eventId) { EventJpaEntity eventEntity = eventJpaRepository.findById(eventId) .orElseThrow(() -> new CustomRuntimeException(ErrorCode.EVENT_NOT_FOUND)); - eventEntity.update(request.title(), request.duration().toDurationJpaVO(), + eventEntity.update( + request.attachment().fileName(), + request.attachment().s3Key(), + request.title(), + request.duration().toDurationJpaVO(), request.eventLink()); eventJpaRepository.save(eventEntity); - attachmentService.deleteAttachment(eventEntity); - attachmentService.createAttachment(request.optionalAttachment(), eventEntity); +// attachmentService.deleteAttachment(eventEntity); +// attachmentService.createAttachment(request.optionalAttachment(), eventEntity); } @Transactional @@ -73,7 +90,6 @@ public void deleteEvent(Long eventId) { .orElseThrow(() -> new CustomRuntimeException(ErrorCode.FILE_NOT_FOUND)); eventJpaRepository.delete(eventEntity); - attachmentService.deleteAttachment(eventEntity); } } diff --git a/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java b/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java index dc066433..ce5638aa 100644 --- a/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java +++ b/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java @@ -19,7 +19,7 @@ public class ExamService { public void register(ExamRequest request) { ExamJpaEntity exam = request.toEntity(); - ExamJpaEntity savedExam = examJpaRepository.save(exam); + examJpaRepository.save(exam); } public List getByArea(String areaName) { @@ -29,7 +29,7 @@ public List getByArea(String areaName) { return foundExams.stream() .map(exam -> { Long count = examQuotaCacheManager.getCurrentApplications( - exam.getSchoolName()).orElse(0L); + exam.getSchoolName()).orElse(null); return ExamResponse.of(exam, count); }) .toList(); @@ -46,10 +46,13 @@ public List getExams() { return exams.stream() .map(exam -> { Long count = examQuotaCacheManager.getCurrentApplications( - exam.getSchoolName()).orElse(0L); - return ExamResponse.of(exam, 3L); + exam.getSchoolName()).orElse(null); + return ExamResponse.of(exam, count); }) .toList(); } + public void delete(Long examId) { + examJpaRepository.deleteById(examId); + } } diff --git a/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryAnswerService.java b/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryAnswerService.java index b7049870..277cf725 100644 --- a/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryAnswerService.java +++ b/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryAnswerService.java @@ -48,7 +48,6 @@ public void deleteInquiryAnswer(Long postId) { .orElseThrow(() -> new CustomRuntimeException(ErrorCode.INQUIRY_ANSWER_NOT_FOUND)); inquiryAnswerJpaRepository.delete(answerEntity); - answerAttachmentService.deleteAttachment(answerEntity); inquiryEntity.updateStatusToPending(); } @@ -73,7 +72,7 @@ public void updateInquiryAnswer(Long postId, InquiryAnswerUpdateRequest request) answerEntity.update(request.title(), request.content()); inquiryAnswerJpaRepository.save(answerEntity); - answerAttachmentService.deleteAttachment(answerEntity); +// answerAttachmentService.deleteAttachment(answerEntity); answerAttachmentService.createAttachment(request.attachments(), answerEntity); } diff --git a/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java b/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java index ecd86ef1..cab266f0 100644 --- a/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java +++ b/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java @@ -66,7 +66,7 @@ public void deleteInquiry(UserJpaEntity user, Long postId) { inquiryAnswerService.deleteInquiryAnswer(postId); }); - inquiryAttachmentService.deleteAttachment(inquiry); +// inquiryAttachmentService.deleteAttachment(inquiry); inquiryJpaRepository.delete(inquiry); } diff --git a/src/main/java/life/mosu/mosuserver/application/notice/NoticeAttachmentService.java b/src/main/java/life/mosu/mosuserver/application/notice/NoticeAttachmentService.java index 63f362a7..558784da 100644 --- a/src/main/java/life/mosu/mosuserver/application/notice/NoticeAttachmentService.java +++ b/src/main/java/life/mosu/mosuserver/application/notice/NoticeAttachmentService.java @@ -9,7 +9,6 @@ import life.mosu.mosuserver.infra.persistence.s3.S3Service; import life.mosu.mosuserver.presentation.common.FileRequest; import life.mosu.mosuserver.presentation.notice.dto.NoticeDetailResponse; -import life.mosu.mosuserver.presentation.notice.dto.NoticeResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -41,18 +40,18 @@ public void deleteAttachment(NoticeJpaEntity entity) { noticeAttachmentJpaRepository.deleteAll(attachments); } - public List toAttachmentResponses(NoticeJpaEntity notice) { - - List attachments = noticeAttachmentJpaRepository.findAllByNoticeId( - notice.getId()); - - return attachments.stream() - .map(attachment -> new NoticeResponse.AttachmentResponse( - attachment.getFileName(), - fileUrl(attachment.getS3Key()) - )) - .toList(); - } +// public List toAttachmentResponses(NoticeJpaEntity notice) { +// +// List attachments = noticeAttachmentJpaRepository.findAllByNoticeId( +// notice.getId()); +// +// return attachments.stream() +// .map(attachment -> new NoticeResponse.AttachmentResponse( +// attachment.getFileName(), +// fileUrl(attachment.getS3Key()) +// )) +// .toList(); +// } public List toDetailAttResponses( NoticeJpaEntity notice) { diff --git a/src/main/java/life/mosu/mosuserver/application/notice/NoticeService.java b/src/main/java/life/mosu/mosuserver/application/notice/NoticeService.java index 3baab088..b312f221 100644 --- a/src/main/java/life/mosu/mosuserver/application/notice/NoticeService.java +++ b/src/main/java/life/mosu/mosuserver/application/notice/NoticeService.java @@ -10,6 +10,7 @@ import life.mosu.mosuserver.presentation.notice.dto.NoticeResponse; import life.mosu.mosuserver.presentation.notice.dto.NoticeUpdateRequest; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -18,6 +19,7 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +@Slf4j @Service @RequiredArgsConstructor public class NoticeService { @@ -32,7 +34,7 @@ public void createNotice(NoticeCreateRequest request) { } @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) - public List getNoticeWithAttachments(int page, int size) { + public List getNotices(int page, int size) { Pageable pageable = PageRequest.of(page, size, Sort.by("id")); Page noticePage = noticeJpaRepository.findAll(pageable); @@ -52,7 +54,6 @@ public NoticeDetailResponse getNoticeDetail(Long noticeId) { public void deleteNotice(Long noticeId) { NoticeJpaEntity noticeEntity = getNoticeOrThrow(noticeId); noticeJpaRepository.delete(noticeEntity); - attachmentService.deleteAttachment(noticeEntity); } @Transactional @@ -65,7 +66,7 @@ public void updateNotice(Long noticeId, NoticeUpdateRequest request) { } private NoticeResponse toNoticeResponse(NoticeJpaEntity notice) { - return NoticeResponse.of(notice, attachmentService.toAttachmentResponses(notice)); + return NoticeResponse.of(notice); } diff --git a/src/main/java/life/mosu/mosuserver/domain/application/ApplicationJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/application/ApplicationJpaEntity.java index 4161aa84..aefec373 100644 --- a/src/main/java/life/mosu/mosuserver/domain/application/ApplicationJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/application/ApplicationJpaEntity.java @@ -6,19 +6,17 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import life.mosu.mosuserver.domain.base.BaseTimeEntity; +import life.mosu.mosuserver.domain.base.BaseDeleteEntity; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.SoftDelete; @Entity @Table(name = "application") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@SoftDelete -public class ApplicationJpaEntity extends BaseTimeEntity { +public class ApplicationJpaEntity extends BaseDeleteEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/life/mosu/mosuserver/domain/base/BaseDeleteEntity.java b/src/main/java/life/mosu/mosuserver/domain/base/BaseDeleteEntity.java index d9c9a125..aa7db11f 100644 --- a/src/main/java/life/mosu/mosuserver/domain/base/BaseDeleteEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/base/BaseDeleteEntity.java @@ -2,14 +2,38 @@ import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Getter @MappedSuperclass +@EntityListeners(AuditingEntityListener.class) public abstract class BaseDeleteEntity { + @CreatedDate + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt; + @Column(name = "deleted") private Boolean deleted = false; + public static String formatDate(LocalDateTime dateTime) { + return dateTime != null ? dateTime.toLocalDate().toString() : null; + } + + public String getCreatedAt() { + return createdAt != null ? createdAt.format( + DateTimeFormatter.ofPattern("yyyy-MM-dd")) : null; + } + } \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/domain/base/BaseTimeEntity.java b/src/main/java/life/mosu/mosuserver/domain/base/BaseTimeEntity.java index 1711cb58..3b675925 100644 --- a/src/main/java/life/mosu/mosuserver/domain/base/BaseTimeEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/base/BaseTimeEntity.java @@ -23,9 +23,6 @@ public abstract class BaseTimeEntity { @Column(name = "updated_at") private LocalDateTime updatedAt; - @Column(name = "is_deleted", nullable = false) - private Boolean deleted = false; - public static String formatDate(LocalDateTime dateTime) { return dateTime != null ? dateTime.toLocalDate().toString() : null; } diff --git a/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentJpaEntity.java index a4761b1a..d826b6f0 100644 --- a/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentJpaEntity.java @@ -1,36 +1,38 @@ -package life.mosu.mosuserver.domain.event; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import life.mosu.mosuserver.domain.file.File; -import life.mosu.mosuserver.domain.file.Visibility; -import lombok.Builder; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Entity -@RequiredArgsConstructor -@Getter -@Table(name = "event_attachment") -public class EventAttachmentJpaEntity extends File { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "event_attachment_id", nullable = false) - private Long id; - - @Column(name = "event_id", nullable = false) - private Long eventId; - - @Builder - public EventAttachmentJpaEntity(final String fileName, final String s3Key, - final Visibility visibility, final Long eventId) { - super(fileName, s3Key, visibility); - this.eventId = eventId; - } - -} +//package life.mosu.mosuserver.domain.event; +// +//import jakarta.persistence.Column; +//import jakarta.persistence.Entity; +//import jakarta.persistence.GeneratedValue; +//import jakarta.persistence.GenerationType; +//import jakarta.persistence.Id; +//import jakarta.persistence.Table; +//import life.mosu.mosuserver.domain.file.File; +//import life.mosu.mosuserver.domain.file.Visibility; +//import lombok.Builder; +//import lombok.Getter; +//import lombok.RequiredArgsConstructor; +// +//@Entity +//@RequiredArgsConstructor +//@Getter +//@Table(name = "event_attachment") +//public class EventAttachmentJpaEntity extends File { +// +// @Id +// @GeneratedValue(strategy = GenerationType.IDENTITY) +// @Column(name = "event_attachment_id", nullable = false) +// private Long id; +// +// @Column(name = "event_id", nullable = false) +// private Long eventId; +// +// @Builder +// public EventAttachmentJpaEntity(final String fileName, final String s3Key, +// final Visibility visibility, final Long eventId) { +// super(fileName, s3Key, visibility); +// this.eventId = eventId; +// } +// +// protected void updateFile() +// +//} diff --git a/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentRepository.java b/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentRepository.java index 85a5547c..f4b0983e 100644 --- a/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentRepository.java +++ b/src/main/java/life/mosu/mosuserver/domain/event/EventAttachmentRepository.java @@ -1,12 +1,12 @@ -package life.mosu.mosuserver.domain.event; - -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface EventAttachmentRepository extends JpaRepository { - - void deleteByEventId(Long eventId); - - Optional findByEventId(Long eventId); -} - +//package life.mosu.mosuserver.domain.event; +// +//import java.util.Optional; +//import org.springframework.data.jpa.repository.JpaRepository; +// +//public interface EventAttachmentRepository extends JpaRepository { +// +// void deleteByEventId(Long eventId); +// +// Optional findByEventId(Long eventId); +//} +// diff --git a/src/main/java/life/mosu/mosuserver/domain/event/EventImage.java b/src/main/java/life/mosu/mosuserver/domain/event/EventImage.java deleted file mode 100644 index e29fdad8..00000000 --- a/src/main/java/life/mosu/mosuserver/domain/event/EventImage.java +++ /dev/null @@ -1,20 +0,0 @@ -package life.mosu.mosuserver.domain.event; - -import jakarta.persistence.Embeddable; -import life.mosu.mosuserver.domain.file.File; -import life.mosu.mosuserver.domain.file.Visibility; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@Embeddable -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class EventImage extends File { - - @Builder - public EventImage(String fileName, String s3Key, Visibility visibility) { - super(fileName, s3Key, visibility); - } -} diff --git a/src/main/java/life/mosu/mosuserver/domain/event/EventJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/event/EventJpaEntity.java index 36d2302c..64428db4 100644 --- a/src/main/java/life/mosu/mosuserver/domain/event/EventJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/event/EventJpaEntity.java @@ -7,17 +7,20 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import life.mosu.mosuserver.domain.base.BaseTimeEntity; +import life.mosu.mosuserver.domain.file.FileWithTime; +import life.mosu.mosuserver.domain.file.Visibility; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Getter @Entity @Table(name = "event") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class EventJpaEntity extends BaseTimeEntity { +@SoftDelete +public class EventJpaEntity extends FileWithTime { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -35,16 +38,27 @@ public class EventJpaEntity extends BaseTimeEntity { @Builder public EventJpaEntity( + final String fileName, + final String s3Key, final String title, + final Visibility visibility, final DurationJpaVO duration, final String eventLink ) { + super(fileName, s3Key, visibility); this.title = title; this.duration = duration; this.eventLink = eventLink; } - public void update(final String title, final DurationJpaVO duration, final String eventLink) { + public void update( + final String fileName, + final String s3Key, + final String title, + final DurationJpaVO duration, + final String eventLink + ) { + updateFile(fileName, s3Key); this.title = title; this.duration = duration; this.eventLink = eventLink; diff --git a/src/main/java/life/mosu/mosuserver/domain/event/EventJpaRepository.java b/src/main/java/life/mosu/mosuserver/domain/event/EventJpaRepository.java index d1e2bee9..6803fd87 100644 --- a/src/main/java/life/mosu/mosuserver/domain/event/EventJpaRepository.java +++ b/src/main/java/life/mosu/mosuserver/domain/event/EventJpaRepository.java @@ -1,45 +1,41 @@ package life.mosu.mosuserver.domain.event; -import java.util.List; -import java.util.Optional; -import life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; public interface EventJpaRepository extends JpaRepository { - @Query(""" - select new life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection( - e.id, - e.title, - e.duration.endDate, - e.eventLink, - new life.mosu.mosuserver.domain.event.projection.AttachmentProjection( - ea.fileName, - ea.s3Key - ) - ) - from EventJpaEntity e - left join EventAttachmentJpaEntity ea - on e.id = ea.eventId - """) - List findAllWithAttachment(); +// @Query(""" +// select new life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection( +// e.id, +// e.title, +// e.duration.endDate, +// e.eventLink, +// new life.mosu.mosuserver.domain.event.projection.AttachmentProjection( +// ea.fileName, +// ea.s3Key +// ) +// ) +// from EventJpaEntity e +// left join EventAttachmentJpaEntity ea +// on e.id = ea.eventId +// """) +// List findAllWithAttachment(); - @Query(""" - select new life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection( - e.id, - e.title, - e.duration.endDate, - e.eventLink, - new life.mosu.mosuserver.domain.event.projection.AttachmentProjection( - ea.fileName, - ea.s3Key - ) - ) - from EventJpaEntity e - left join EventAttachmentJpaEntity ea - on e.id = ea.eventId - WHERE e.id = :id - """) - Optional findWithAttachmentById(Long id); +// @Query(""" +// select new life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection( +// e.id, +// e.title, +// e.duration.endDate, +// e.eventLink, +// new life.mosu.mosuserver.domain.event.projection.AttachmentProjection( +// ea.fileName, +// ea.s3Key +// ) +// ) +// from EventJpaEntity e +// left join EventAttachmentJpaEntity ea +// on e.id = ea.eventId +// WHERE e.id = :id +// """) +// Optional findWithAttachmentById(Long id); } diff --git a/src/main/java/life/mosu/mosuserver/domain/event/EventQueryRepository.java b/src/main/java/life/mosu/mosuserver/domain/event/EventQueryRepository.java new file mode 100644 index 00000000..b90d9b9f --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/domain/event/EventQueryRepository.java @@ -0,0 +1,9 @@ +package life.mosu.mosuserver.domain.event; + +import org.springframework.data.domain.Slice; + +public interface EventQueryRepository { + + Slice findAllByCursorId(Long cursorId); + +} diff --git a/src/main/java/life/mosu/mosuserver/domain/event/projection/EventWithAttachmentProjection.java b/src/main/java/life/mosu/mosuserver/domain/event/projection/EventWithAttachmentProjection.java index e0322dd9..f41accfe 100644 --- a/src/main/java/life/mosu/mosuserver/domain/event/projection/EventWithAttachmentProjection.java +++ b/src/main/java/life/mosu/mosuserver/domain/event/projection/EventWithAttachmentProjection.java @@ -1,13 +1,13 @@ -package life.mosu.mosuserver.domain.event.projection; - -import java.time.LocalDate; - -public record EventWithAttachmentProjection( - Long eventId, - String title, - LocalDate endDate, - String eventLink, - AttachmentProjection attachment -) { - -} \ No newline at end of file +//package life.mosu.mosuserver.domain.event.projection; +// +//import java.time.LocalDate; +// +//public record EventWithAttachmentProjection( +// Long eventId, +// String title, +// LocalDate endDate, +// String eventLink, +// AttachmentProjection attachment +//) { +// +//} \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/domain/exam/ExamJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/exam/ExamJpaEntity.java index 30322b05..09007670 100644 --- a/src/main/java/life/mosu/mosuserver/domain/exam/ExamJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/exam/ExamJpaEntity.java @@ -12,16 +12,19 @@ import jakarta.persistence.Table; import java.time.LocalDate; import java.time.LocalDateTime; +import life.mosu.mosuserver.domain.base.BaseTimeEntity; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Getter @Entity @Table(name = "exam") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class ExamJpaEntity { +@SoftDelete +public class ExamJpaEntity extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaEntity.java index 5ceb84e4..3b3563a7 100644 --- a/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaEntity.java @@ -6,7 +6,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import life.mosu.mosuserver.domain.base.BaseTimeEntity; +import life.mosu.mosuserver.domain.base.BaseDeleteEntity; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -18,7 +18,7 @@ @Table(name = "exam_application") @Slf4j @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class ExamApplicationJpaEntity extends BaseTimeEntity { +public class ExamApplicationJpaEntity extends BaseDeleteEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -63,7 +63,7 @@ public static ExamApplicationJpaEntity create( .isLunchChecked(isLunchChecked) .build(); - log.info("check : {}", e.getDeleted()); +// log.info("check : {}", e.getDeleted()); return e; } diff --git a/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamSubjectJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamSubjectJpaEntity.java index 869cc4ea..b557eb0b 100644 --- a/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamSubjectJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/examapplication/ExamSubjectJpaEntity.java @@ -9,7 +9,6 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import life.mosu.mosuserver.domain.application.Subject; -import life.mosu.mosuserver.domain.base.BaseDeleteEntity; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -19,7 +18,7 @@ @Entity @Table(name = "exam_subject") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class ExamSubjectJpaEntity extends BaseDeleteEntity { +public class ExamSubjectJpaEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/life/mosu/mosuserver/domain/faq/FaqJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/faq/FaqJpaEntity.java index d67c2df2..15dedf57 100644 --- a/src/main/java/life/mosu/mosuserver/domain/faq/FaqJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/faq/FaqJpaEntity.java @@ -10,11 +10,13 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Getter @Entity @Table(name = "faq") @NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) +@SoftDelete public class FaqJpaEntity extends BaseTimeEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/file/AdmissionTicketFileEntity.java b/src/main/java/life/mosu/mosuserver/domain/file/AdmissionTicketFileEntity.java deleted file mode 100644 index 5c253f15..00000000 --- a/src/main/java/life/mosu/mosuserver/domain/file/AdmissionTicketFileEntity.java +++ /dev/null @@ -1,33 +0,0 @@ -package life.mosu.mosuserver.domain.file; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "admission_ticket_file") -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class AdmissionTicketFileEntity extends File { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "user_id") - private Long userId; - - @Builder - public AdmissionTicketFileEntity(Long userId, String fileName, String s3Key, - Visibility visibility) { - super(fileName, s3Key, visibility); - this.userId = userId; - } -} diff --git a/src/main/java/life/mosu/mosuserver/domain/file/File.java b/src/main/java/life/mosu/mosuserver/domain/file/File.java index 47fce8b3..b9ae33fb 100644 --- a/src/main/java/life/mosu/mosuserver/domain/file/File.java +++ b/src/main/java/life/mosu/mosuserver/domain/file/File.java @@ -4,7 +4,6 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.MappedSuperclass; -import life.mosu.mosuserver.domain.base.BaseDeleteEntity; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,7 +11,7 @@ @Getter @MappedSuperclass @NoArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class File extends BaseDeleteEntity { +public abstract class File { @Column private String fileName; @@ -21,7 +20,7 @@ public abstract class File extends BaseDeleteEntity { private String s3Key; @Enumerated(EnumType.STRING) - @Column(nullable = false) + @Column private Visibility visibility; protected File(String fileName, String s3Key, Visibility visibility) { diff --git a/src/main/java/life/mosu/mosuserver/domain/file/FileWithTime.java b/src/main/java/life/mosu/mosuserver/domain/file/FileWithTime.java index 18618214..b179b6ff 100644 --- a/src/main/java/life/mosu/mosuserver/domain/file/FileWithTime.java +++ b/src/main/java/life/mosu/mosuserver/domain/file/FileWithTime.java @@ -21,7 +21,7 @@ public abstract class FileWithTime extends BaseTimeEntity { private String s3Key; @Enumerated(EnumType.STRING) - @Column(nullable = false) + @Column private Visibility visibility; protected FileWithTime(String fileName, String s3Key, Visibility visibility) { @@ -33,4 +33,9 @@ protected FileWithTime(String fileName, String s3Key, Visibility visibility) { public boolean isPublic() { return this.visibility.equals(Visibility.PUBLIC); } + + protected void updateFile(String fileName, String s3Key) { + this.fileName = fileName; + this.s3Key = s3Key; + } } \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryAttachmentJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryAttachmentJpaEntity.java index c36015a6..d9970211 100644 --- a/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryAttachmentJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryAttachmentJpaEntity.java @@ -11,7 +11,6 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.SoftDelete; @Getter @Entity diff --git a/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryJpaEntity.java index 22045643..6967176f 100644 --- a/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/inquiry/InquiryJpaEntity.java @@ -12,11 +12,13 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Getter @Entity @Table(name = "inquiry") @NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) +@SoftDelete public class InquiryJpaEntity extends BaseTimeEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerAttachmentEntity.java b/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerAttachmentEntity.java index 4af97937..21a1233b 100644 --- a/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerAttachmentEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerAttachmentEntity.java @@ -11,7 +11,6 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.hibernate.annotations.SoftDelete; @Getter diff --git a/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerJpaEntity.java index 33b342b4..2cc781d4 100644 --- a/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/inquiryAnswer/InquiryAnswerJpaEntity.java @@ -11,11 +11,13 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Getter @Entity @Table(name = "inquiry_answer") @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SoftDelete public class InquiryAnswerJpaEntity extends BaseTimeEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/lunch/LunchJpaRepository.java b/src/main/java/life/mosu/mosuserver/domain/lunch/LunchJpaRepository.java deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/java/life/mosu/mosuserver/domain/notice/NoticeJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/notice/NoticeJpaEntity.java index 48a9c491..590c868e 100644 --- a/src/main/java/life/mosu/mosuserver/domain/notice/NoticeJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/notice/NoticeJpaEntity.java @@ -11,11 +11,13 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Getter @Entity @Table(name = "notice") @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SoftDelete public class NoticeJpaEntity extends BaseTimeEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/notify/NotifyJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/notify/NotifyJpaEntity.java index eb57953c..1f4b3662 100644 --- a/src/main/java/life/mosu/mosuserver/domain/notify/NotifyJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/notify/NotifyJpaEntity.java @@ -12,12 +12,14 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Entity @Getter @Table(name = "notify") @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SoftDelete public class NotifyJpaEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java index c8d1c4e1..4fd91db1 100644 --- a/src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java @@ -9,7 +9,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import life.mosu.mosuserver.domain.base.BaseTimeEntity; +import life.mosu.mosuserver.domain.base.BaseDeleteEntity; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -19,7 +19,7 @@ @Getter @Table(name = "payment") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class PaymentJpaEntity extends BaseTimeEntity { +public class PaymentJpaEntity extends BaseDeleteEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/life/mosu/mosuserver/domain/profile/ProfileJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/profile/ProfileJpaEntity.java index 8e55a9a2..d7f6348a 100644 --- a/src/main/java/life/mosu/mosuserver/domain/profile/ProfileJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/profile/ProfileJpaEntity.java @@ -17,12 +17,14 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Entity @Getter @Table(name = "profile", uniqueConstraints = @UniqueConstraint(columnNames = "user_id")) @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SoftDelete public class ProfileJpaEntity extends BaseTimeEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/recommendation/RecommendationJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/recommendation/RecommendationJpaEntity.java index 10470f1e..cea67d58 100644 --- a/src/main/java/life/mosu/mosuserver/domain/recommendation/RecommendationJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/recommendation/RecommendationJpaEntity.java @@ -10,11 +10,13 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Entity @Table(name = "recommendation") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SoftDelete public class RecommendationJpaEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java index 8a6ccbdd..c1d20f6d 100644 --- a/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java @@ -8,7 +8,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import life.mosu.mosuserver.domain.base.BaseTimeEntity; +import life.mosu.mosuserver.domain.base.BaseDeleteEntity; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -18,7 +18,7 @@ @Getter @Table(name = "refund") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class RefundJpaEntity extends BaseTimeEntity { +public class RefundJpaEntity extends BaseDeleteEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/life/mosu/mosuserver/domain/school/SchoolLunchJpaRepository.java b/src/main/java/life/mosu/mosuserver/domain/school/SchoolLunchJpaRepository.java deleted file mode 100644 index 9dfcf828..00000000 --- a/src/main/java/life/mosu/mosuserver/domain/school/SchoolLunchJpaRepository.java +++ /dev/null @@ -1,3 +0,0 @@ -public class SchoolLunchJpaRepository { - -} diff --git a/src/main/java/life/mosu/mosuserver/domain/user/UserJpaEntity.java b/src/main/java/life/mosu/mosuserver/domain/user/UserJpaEntity.java index fc5cf154..a0ac69e2 100644 --- a/src/main/java/life/mosu/mosuserver/domain/user/UserJpaEntity.java +++ b/src/main/java/life/mosu/mosuserver/domain/user/UserJpaEntity.java @@ -17,11 +17,13 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SoftDelete; @Entity @Table(name = "user") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SoftDelete public class UserJpaEntity extends BaseTimeEntity { @Id diff --git a/src/main/java/life/mosu/mosuserver/global/annotation/CursorParam.java b/src/main/java/life/mosu/mosuserver/global/annotation/CursorParam.java new file mode 100644 index 00000000..85a74f70 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/global/annotation/CursorParam.java @@ -0,0 +1,12 @@ +package life.mosu.mosuserver.global.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface CursorParam { + +} diff --git a/src/main/java/life/mosu/mosuserver/global/support/Cursor.java b/src/main/java/life/mosu/mosuserver/global/support/Cursor.java new file mode 100644 index 00000000..81e188d5 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/global/support/Cursor.java @@ -0,0 +1,27 @@ +package life.mosu.mosuserver.global.support; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Getter +@EqualsAndHashCode +public class Cursor { + + private final Long id; + + @JsonCreator + public Cursor(@JsonProperty("id") final Long id) { + this.id = id; + } + + public static Cursor empty() { + return new Cursor(null); + } + + public static Cursor of(final Long id) { + return new Cursor(id); + } + +} diff --git a/src/main/java/life/mosu/mosuserver/global/support/CursorArgumentResolver.java b/src/main/java/life/mosu/mosuserver/global/support/CursorArgumentResolver.java new file mode 100644 index 00000000..d9b0b516 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/global/support/CursorArgumentResolver.java @@ -0,0 +1,37 @@ +package life.mosu.mosuserver.global.support; + +import com.fasterxml.jackson.databind.ObjectMapper; +import life.mosu.mosuserver.global.annotation.CursorParam; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +@RequiredArgsConstructor +public class CursorArgumentResolver implements HandlerMethodArgumentResolver { + + private final ObjectMapper objectMapper; + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(CursorParam.class) && + parameter.getParameterType().equals(Cursor.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + + String cursorJson = webRequest.getParameter("id"); + + if (cursorJson == null || cursorJson.isBlank()) { + return Cursor.empty(); + } + + return objectMapper.readValue(cursorJson, Cursor.class); + } +} diff --git a/src/main/java/life/mosu/mosuserver/global/support/CursorResponse.java b/src/main/java/life/mosu/mosuserver/global/support/CursorResponse.java new file mode 100644 index 00000000..3b282f27 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/global/support/CursorResponse.java @@ -0,0 +1,52 @@ +package life.mosu.mosuserver.global.support; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.domain.Slice; + +@Getter +public class CursorResponse { + + private final List content; + private final SliceInfo sliceInfo; + + private CursorResponse(final List content, final SliceInfo sliceInfo) { + this.content = content; + this.sliceInfo = sliceInfo; + } + + public static CursorResponse of(final Slice slice, final Long cursor) { + SliceInfo pageInfo = SliceInfo.builder() + .numberOfElements(slice.getNumberOfElements()) + .last(slice.isLast()) + .nextCursor(cursor) + .build(); + return new CursorResponse<>(slice.getContent(), pageInfo); + } + + public static CursorResponse of( + final List content, + final boolean last, + final int numberOfElements, + final Long nextCursor + ) { + SliceInfo pageInfo = SliceInfo.builder() + .numberOfElements(numberOfElements) + .last(last) + .nextCursor(nextCursor) + .build(); + return new CursorResponse<>(content, pageInfo); + } + + record SliceInfo( + int numberOfElements, + boolean last, + Long nextCursor + ) { + + @Builder + public SliceInfo { + } + } +} \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/EventQueryRepositoryImpl.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/EventQueryRepositoryImpl.java new file mode 100644 index 00000000..ae486c12 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/EventQueryRepositoryImpl.java @@ -0,0 +1,44 @@ +package life.mosu.mosuserver.infra.persistence.jpa; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import life.mosu.mosuserver.domain.event.EventJpaEntity; +import life.mosu.mosuserver.domain.event.EventQueryRepository; +import life.mosu.mosuserver.domain.event.QEventJpaEntity; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class EventQueryRepositoryImpl implements EventQueryRepository { + + private static final int SIZE = 20; + + private final JPAQueryFactory queryFactory; + private final QEventJpaEntity event = QEventJpaEntity.eventJpaEntity; + + @Override + public Slice findAllByCursorId(Long cursorId) { + List events = fetchEvents(cursorId); + return toSlice(events); + } + + private List fetchEvents(Long cursorId) { + return queryFactory.selectFrom(event) + .where((cursorId == null || cursorId == -1) ? null : event.id.lt(cursorId)) + .orderBy(event.id.desc()) + .limit(SIZE + 1) + .fetch(); + } + + private Slice toSlice(List events) { + boolean hasNext = events.size() > SIZE; + List content = hasNext ? events.subList(0, SIZE) : events; + Pageable pageable = PageRequest.of(0, SIZE); + return new SliceImpl<>(content, pageable, hasNext); + } +} diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ExamApplicationBulkRepository.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ExamApplicationBulkRepository.java index 0916a409..dbe4d822 100644 --- a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ExamApplicationBulkRepository.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ExamApplicationBulkRepository.java @@ -29,8 +29,8 @@ public class ExamApplicationBulkRepository { private static final String SQL_INSERT_EXAM_APPLICATION = """ INSERT INTO exam_application (created_at, updated_at, application_id, - user_id, exam_id, lunch_checked, exam_number, is_deleted) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) + user_id, exam_id, lunch_checked, exam_number) + VALUES (?, ?, ?, ?, ?, ?, ?) """; private static final String SQL_INSERT_EXAM_SUBJECT = """ INSERT INTO exam_subject (exam_application_id, subject) VALUES (?, ?) @@ -53,7 +53,7 @@ public List saveAllExamApplicationsWithSubjects( ps.setLong(5, e.getExamId()); ps.setBoolean(6, e.getIsLunchChecked()); ps.setString(7, e.getExamNumber()); - ps.setBoolean(8, e.getDeleted()); +// ps.setBoolean(8, e.getDeleted()); ps.addBatch(); log.info( diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/dto/BannerInfoResponse.java b/src/main/java/life/mosu/mosuserver/presentation/admin/dto/BannerInfoResponse.java index 75b5abd6..56e01321 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/dto/BannerInfoResponse.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/dto/BannerInfoResponse.java @@ -1,12 +1,13 @@ package life.mosu.mosuserver.presentation.admin.dto; +import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; public record BannerInfoResponse( String title, LocalDateTime deadLine, String link, - String imgUrl + AttachmentResponse attachment ) { @@ -14,9 +15,21 @@ public static BannerInfoResponse of( String title, LocalDateTime deadLine, String link, - String imgUrl + AttachmentResponse attachment ) { - return new BannerInfoResponse(title, deadLine, link, imgUrl); + return new BannerInfoResponse(title, deadLine, link, attachment); + } + + + public record AttachmentResponse( + @Schema(description = "파일 이름", example = "image.png") + String fileName, + @Schema(description = "파일 URL", example = "https://example.com/image.png") + String url) { + + public static AttachmentResponse of(String fileName, String url) { + return new AttachmentResponse(fileName, url); + } } } diff --git a/src/main/java/life/mosu/mosuserver/presentation/common/FileRequest.java b/src/main/java/life/mosu/mosuserver/presentation/common/FileRequest.java index 96fa355b..6a35c190 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/common/FileRequest.java +++ b/src/main/java/life/mosu/mosuserver/presentation/common/FileRequest.java @@ -2,7 +2,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import life.mosu.mosuserver.domain.application.ExamTicketImageJpaEntity; -import life.mosu.mosuserver.domain.event.EventAttachmentJpaEntity; import life.mosu.mosuserver.domain.file.Visibility; import life.mosu.mosuserver.domain.inquiry.InquiryAttachmentJpaEntity; import life.mosu.mosuserver.domain.inquiryAnswer.InquiryAnswerAttachmentEntity; @@ -56,12 +55,12 @@ public InquiryAnswerAttachmentEntity toInquiryAnswerAttachmentEntity(Long inquir .build(); } - public EventAttachmentJpaEntity toEventAttachmentEntity(Long eventId) { - return EventAttachmentJpaEntity.builder() - .fileName(fileName) - .s3Key(s3Key) - .visibility(Visibility.PUBLIC) - .eventId(eventId) - .build(); - } +// public EventAttachmentJpaEntity toEventAttachmentEntity(Long eventId) { +// return EventAttachmentJpaEntity.builder() +// .fileName(fileName) +// .s3Key(s3Key) +// .visibility(Visibility.PUBLIC) +// .eventId(eventId) +// .build(); +// } } diff --git a/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java b/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java index fa297e06..4a440e74 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java @@ -1,8 +1,10 @@ package life.mosu.mosuserver.presentation.event; import jakarta.validation.Valid; -import java.util.List; import life.mosu.mosuserver.application.event.EventService; +import life.mosu.mosuserver.global.annotation.CursorParam; +import life.mosu.mosuserver.global.support.Cursor; +import life.mosu.mosuserver.global.support.CursorResponse; import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.event.dto.EventRequest; import life.mosu.mosuserver.presentation.event.dto.EventResponse; @@ -22,7 +24,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/event") -public class EventController implements EventControllerDocs { +public class EventController { private final EventService eventService; @@ -35,9 +37,10 @@ public ResponseEntity> createEvent( } @GetMapping("/list") - public ResponseEntity>> getEvents( + public ResponseEntity>> getEvents( + @CursorParam Cursor cursor ) { - List responses = eventService.getEvents(); + CursorResponse responses = eventService.getEvents(cursor.getId()); return ResponseEntity.ok( ApiResponseWrapper.success(HttpStatus.OK, "이벤트 조회 성공", responses)); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventRequest.java b/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventRequest.java index ffaaaf2d..306e68e5 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventRequest.java +++ b/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventRequest.java @@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotBlank; import java.util.List; import life.mosu.mosuserver.domain.event.EventJpaEntity; +import life.mosu.mosuserver.domain.file.Visibility; import life.mosu.mosuserver.presentation.common.FileRequest; @Schema(description = "이벤트 등록/수정 요청 DTO") @@ -34,6 +35,9 @@ public EventJpaEntity toEntity() { .title(title) .eventLink(eventLink) .duration(duration.toDurationJpaVO()) + .fileName(attachment().fileName()) + .s3Key(attachment().s3Key()) + .visibility(Visibility.PUBLIC) .build(); } } diff --git a/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventResponse.java b/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventResponse.java index aa24fa2e..2c6652de 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventResponse.java +++ b/src/main/java/life/mosu/mosuserver/presentation/event/dto/EventResponse.java @@ -2,7 +2,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDate; -import life.mosu.mosuserver.domain.event.projection.EventWithAttachmentProjection; +import life.mosu.mosuserver.domain.event.EventJpaEntity; @Schema(description = "이벤트 응답 DTO") public record EventResponse( @@ -24,18 +24,18 @@ public record EventResponse( ) { - public static EventResponse of(EventWithAttachmentProjection event, String eventUrl) { + public static EventResponse of(EventJpaEntity event, String eventUrl) { AttachmentResponse attachment = new AttachmentResponse( - event.attachment().fileName(), + event.getFileName(), eventUrl, - event.attachment().s3Key() + event.getS3Key() ); return new EventResponse( - event.eventId(), - event.title(), - event.endDate(), - event.eventLink(), + event.getId(), + event.getTitle(), + event.getDuration().getEndDate(), + event.getEventLink(), attachment ); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java b/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java index 5dfdf1ed..4e94d495 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java @@ -8,7 +8,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -23,7 +26,7 @@ public class ExamController { private final ExamService examService; @PostMapping -// @PreAuthorize("isAuthenticated()") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> register( @RequestBody ExamRequest request ) { @@ -51,10 +54,18 @@ public ResponseEntity>> getByArea( } @GetMapping("/areas") -// @PreAuthorize("isAuthenticated()") public ResponseEntity>> getDistinctAreas() { List response = examService.getDistinctAreas(); return ResponseEntity.ok( ApiResponseWrapper.success(HttpStatus.OK, "시험 지역 조회 성공", response)); } + + @DeleteMapping("/{examId}") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + public ResponseEntity> delete(@PathVariable Long examId) { + examService.delete(examId); + return ResponseEntity.ok( + ApiResponseWrapper.success(HttpStatus.OK, "시험장 삭제 성공")); + + } } diff --git a/src/main/java/life/mosu/mosuserver/presentation/notice/NoticeController.java b/src/main/java/life/mosu/mosuserver/presentation/notice/NoticeController.java index b9d51c95..99a5a2c0 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/notice/NoticeController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/notice/NoticeController.java @@ -42,7 +42,7 @@ public ResponseEntity>> getNotices( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size ) { - List notices = noticeService.getNoticeWithAttachments(page, size); + List notices = noticeService.getNotices(page, size); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "게시글 조회 성공", notices)); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/notice/dto/NoticeResponse.java b/src/main/java/life/mosu/mosuserver/presentation/notice/dto/NoticeResponse.java index 59e2e92f..e8800d7f 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/notice/dto/NoticeResponse.java +++ b/src/main/java/life/mosu/mosuserver/presentation/notice/dto/NoticeResponse.java @@ -1,7 +1,6 @@ package life.mosu.mosuserver.presentation.notice.dto; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; import life.mosu.mosuserver.domain.notice.NoticeJpaEntity; public record NoticeResponse( @@ -19,31 +18,31 @@ public record NoticeResponse( String author, @Schema(description = "작성일시 (yyyy-MM-dd)", example = "2025-07-08") - String createdAt, + String createdAt - @Schema(description = "첨부파일 목록") - List attachments +// @Schema(description = "첨부파일 목록") +// List attachments ) { - public static NoticeResponse of(NoticeJpaEntity notice, List attachments) { + public static NoticeResponse of(NoticeJpaEntity notice) { return new NoticeResponse( notice.getId(), notice.getTitle(), notice.getContent(), notice.getAuthor(), - notice.getCreatedAt(), - attachments + notice.getCreatedAt() +// attachments ); } - public record AttachmentResponse( - - @Schema(description = "파일 이름", example = "service_guide.pdf") - String fileName, - - @Schema(description = "S3 Presigned URL", example = "https://bucket.s3.amazonaws.com/.../service_guide.pdf") - String url - ) { - - } +// public record AttachmentResponse( +// +// @Schema(description = "파일 이름", example = "service_guide.pdf") +// String fileName, +// +// @Schema(description = "S3 Presigned URL", example = "https://bucket.s3.amazonaws.com/.../service_guide.pdf") +// String url +// ) { +// +// } } \ No newline at end of file