Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 공지 CRUD API 구현 #323

Merged
merged 11 commits into from
Oct 30, 2024
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.listywave.notice.application.service;

import com.listywave.notice.application.domain.Notice;
import com.listywave.notice.application.domain.NoticeContent;
import com.listywave.notice.application.service.dto.NoticeCreateRequest;
import com.listywave.notice.repository.NoticeRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
public class NoticeService {

private final NoticeRepository noticeRepository;

public Long create(NoticeCreateRequest request) {
Notice notice = request.toNotice();
List<NoticeContent> noticeContents = request.toNoticeContents(notice);
notice.addContents(noticeContents);
return noticeRepository.save(notice).getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.listywave.notice.application.service.dto;

import com.listywave.notice.application.domain.ContentType;
import com.listywave.notice.application.domain.Notice;
import com.listywave.notice.application.domain.NoticeContent;
import com.listywave.notice.application.domain.NoticeDescription;
import com.listywave.notice.application.domain.NoticeTitle;
import com.listywave.notice.application.domain.NoticeType;
import jakarta.annotation.Nullable;
import java.util.List;

public record NoticeCreateRequest(
int categoryCode,
String title,
String description,
List<ContentDto> contents
) {

public record ContentDto(
int order,
String type,
@Nullable String description,
@Nullable String imageUrl,
@Nullable String buttonName,
@Nullable String buttonLink
) {
}

public Notice toNotice() {
return new Notice(NoticeType.codeOf(categoryCode), new NoticeTitle(title), new NoticeDescription(description));
}

public List<NoticeContent> toNoticeContents(Notice notice) {
return contents.stream()
.map(it -> NoticeContent.create(notice,
it.order,
ContentType.valueOf(it.type.toUpperCase()),
it.description,
it.imageUrl,
it.buttonName,
it.buttonLink)
).toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,37 @@
import com.listywave.admin.AdminService;
import com.listywave.common.auth.Auth;
import com.listywave.notice.application.domain.NoticeType;
import com.listywave.notice.application.service.NoticeService;
import com.listywave.notice.application.service.dto.NoticeCreateRequest;
import com.listywave.notice.presentation.dto.NoticeCategoryFindResponse;
import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class NoticeController {

private final AdminService adminService;
private final NoticeService noticeService;

@GetMapping("/admin/notices/categories")
ResponseEntity<List<NoticeCategoryFindResponse>> findNoticeCategories(@Auth Long adminId) {
adminService.validateExist(adminId);
List<NoticeCategoryFindResponse> result = NoticeCategoryFindResponse.toList(NoticeType.values());
return ResponseEntity.ok(result);
}

@PostMapping("/admin/notices")
ResponseEntity<Void> create(
@RequestBody NoticeCreateRequest request
) {
Long id = noticeService.create(request);
return ResponseEntity.created(URI.create("/admin/notices/" + id)).build();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 이게 그 RestFul API 설계 원칙에 HATEOAS 방식을 사용한 건가요? 응답에 uri 넣어주는

Copy link
Collaborator Author

@kdkdhoho kdkdhoho Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이는 HTTP - 201 Created 상태 코드의 명세에 따른 것입니다~!

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.listywave.notice.repository;

import static com.listywave.common.exception.ErrorCode.RESOURCE_NOT_FOUND;

import com.listywave.common.exception.CustomException;
import com.listywave.notice.application.domain.Notice;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NoticeRepository extends JpaRepository<Notice, Long> {

default Notice getById(Long id) {
return findById(id).orElseThrow(() -> new CustomException(RESOURCE_NOT_FOUND, "존재하지 않는 공지입니다."));
}
}
11 changes: 11 additions & 0 deletions src/test/java/com/listywave/common/IntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static com.listywave.user.fixture.UserFixture.유진;
import static com.listywave.user.fixture.UserFixture.정수;

import com.listywave.admin.AdminRepository;
import com.listywave.alarm.application.service.AlarmService;
import com.listywave.alarm.repository.AlarmRepository;
import com.listywave.auth.application.domain.kakao.KakaoOauthClient;
Expand All @@ -23,6 +24,8 @@
import com.listywave.list.repository.list.ListRepository;
import com.listywave.list.repository.reply.ReplyRepository;
import com.listywave.mention.MentionRepository;
import com.listywave.notice.application.service.NoticeService;
import com.listywave.notice.repository.NoticeRepository;
import com.listywave.reaction.repository.ReactionStatsRepository;
import com.listywave.reaction.repository.UserReactionRepository;
import com.listywave.topic.application.service.TopicService;
Expand Down Expand Up @@ -90,12 +93,20 @@ public abstract class IntegrationTest {
protected UserReactionRepository userReactionRepository;
@Autowired
protected ReactionStatsRepository reactionStatsRepository;
@Autowired
protected AdminRepository adminRepository;
@Autowired
protected NoticeService noticeService;
@Autowired
protected NoticeRepository noticeRepository;

protected User dh, js, ej, sy;
protected ListEntity list;

@BeforeEach
void setUp() {
noticeRepository.deleteAll();
adminRepository.deleteAllInBatch();
historyRepository.deleteAll();
userReactionRepository.deleteAllInBatch();
reactionStatsRepository.deleteAllInBatch();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.listywave.notice.application.service;

import static com.listywave.notice.application.domain.NoticeType.NEWS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

import com.listywave.common.IntegrationTest;
import com.listywave.notice.application.domain.Notice;
import com.listywave.notice.application.service.dto.NoticeCreateRequest;
import com.listywave.notice.application.service.dto.NoticeCreateRequest.ContentDto;
import java.util.List;
import org.junit.jupiter.api.Test;

public class NoticeServiceTest extends IntegrationTest {

@Test
void 공지를_생성한다() {
// given
NoticeCreateRequest request = new NoticeCreateRequest(
1,
"공지입니다",
"공지에요",
List.of(
new ContentDto(1, "subtitle", "소제목입니다", null, null, null),
new ContentDto(2, "body", "본문입니다", null, null, null),
new ContentDto(3, "image", "이미지입니다", "https://image.com", null, null),
new ContentDto(4, "button", "버튼입니다", null, "버튼 이름", "https://buttonLink.com"),
new ContentDto(5, "note", "유의사항입니다", null, null, null)
)
);

// when
noticeService.create(request);

// then
Notice result = noticeRepository.getById(1L);
assertAll(
() -> assertThat(result.getType()).isEqualTo(NEWS),
() -> assertThat(result.getTitle().getValue()).isEqualTo("공지입니다"),
() -> assertThat(result.getDescription().getValue()).isEqualTo("공지에요")
// () -> assertThat(result.getContents().size()).isEqualTo(5)
// () -> {
// List<NoticeContent> contents = result.getContents();
//
// ;
// assertAll(
// () -> assertThat(contents.get(0).getOrder()).isEqualTo(1),
// () -> assertThat(contents.get(0).getType()).isEqualTo(SUBTITLE),
// () -> assertThat(contents.get(0).getDescription()).isEqualTo("소제목입니다"),
// () -> assertThat(contents.get(0).getImageUrl())
// .isEqualTo(contents.get(0).getButtonName())
// .isEqualTo(contents.get(0).getButtonLink())
// .isNull()
// );
// }
);
}
}