Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package org.withtime.be.withtimebe.domain.notice.controller.command;

import org.namul.api.payload.response.DefaultResponse;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.withtime.be.withtimebe.domain.member.entity.Member;
import org.withtime.be.withtimebe.domain.notice.converter.NoticeConverter;
import org.withtime.be.withtimebe.domain.notice.dto.request.NoticeRequestDTO;
import org.withtime.be.withtimebe.domain.notice.dto.response.NoticeResponseDTO;
import org.withtime.be.withtimebe.domain.notice.entity.Notice;
import org.withtime.be.withtimebe.domain.notice.service.command.NoticeCommandService;
import org.withtime.be.withtimebe.global.security.annotation.AuthenticatedMember;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/admin/notices")
public class NoticeCommandController {

private final NoticeCommandService noticeCommandService;

@Operation(summary = "공지사항 생성 API Only Admin by 피우", description = "공지사항 생성 API입니다. 어드민만 사용 가능합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(responseCode = "403",
description = """
- COMMON403 : "Admin 권한이 없음을 의미합니다."
""")
})
@PostMapping
public DefaultResponse<NoticeResponseDTO.Notice> createNotice(
@RequestBody @Valid NoticeRequestDTO.CreateNotice request,
@AuthenticatedMember Member member
) {
Notice result = noticeCommandService.createNotice(request, member);
NoticeResponseDTO.Notice response = NoticeConverter.toNotice(result);
return DefaultResponse.created(response);
}

@Operation(summary = "공지사항 수정 API Only Admin by 피우", description = "공지사항 수정 API입니다. 어드민만 사용 가능합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(responseCode = "403",
description = """
- COMMON403 : "Admin 권한이 없음을 의미합니다."
"""),
@ApiResponse(responseCode = "404",
description = """
- NOTICE404_2 : "해당하는 공지사항을 찾을 수 없습니다."
""")
})
@PutMapping("/{noticeId}")
public DefaultResponse<NoticeResponseDTO.Notice> updateNotice(
@PathVariable Long noticeId,
@RequestBody @Valid NoticeRequestDTO.UpdateNotice request
) {
Notice result = noticeCommandService.updateNotice(request, noticeId);
NoticeResponseDTO.Notice response = NoticeConverter.toNotice(result);
return DefaultResponse.ok(response);
}

@Operation(summary = "공지사항 삭제 API Only Admin by 피우", description = "공지사항 삭제 API입니다. 어드민만 사용 가능합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "성공입니다."),
@ApiResponse(responseCode = "403",
description = """
- COMMON403 : "Admin 권한이 없음을 의미합니다."
"""),
@ApiResponse(responseCode = "404",
description = """
- NOTICE404_2 : "해당하는 공지사항을 찾을 수 없습니다."
""")
})
@DeleteMapping("/{noticeId}")
public DefaultResponse<String> softDeleteNotice(@PathVariable Long noticeId) {
noticeCommandService.softDeleteNotice(noticeId);
return DefaultResponse.noContent();
}

@Operation(summary = "삭제한 공지사항 되돌리기 API Only Admin by 피우", description = "삭제한 공지사항을 되돌리는 API입니다. 어드민만 사용 가능합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(responseCode = "403",
description = """
- COMMON403 : "Admin 권한이 없음을 의미합니다."
"""),
@ApiResponse(responseCode = "404",
description = """
- NOTICE404_2 : "해당하는 공지사항을 찾을 수 없습니다."
""")
})
@PatchMapping("/{noticeId}")
public DefaultResponse<NoticeResponseDTO.Notice> recoverDeletedNotice(@PathVariable Long noticeId) {
Notice result = noticeCommandService.recoverDeletedNotice(noticeId);
NoticeResponseDTO.Notice response = NoticeConverter.toNotice(result);
return DefaultResponse.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.withtime.be.withtimebe.domain.notice.controller.query;


import org.namul.api.payload.response.DefaultResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.withtime.be.withtimebe.domain.member.entity.Member;
import org.withtime.be.withtimebe.domain.notice.converter.NoticeConverter;
import org.withtime.be.withtimebe.domain.notice.dto.request.NoticeRequestDTO;
import org.withtime.be.withtimebe.domain.notice.dto.response.NoticeResponseDTO;
import org.withtime.be.withtimebe.domain.notice.entity.Notice;
import org.withtime.be.withtimebe.domain.notice.service.query.NoticeQueryService;
import org.withtime.be.withtimebe.global.annotation.SwaggerPageable;
import org.withtime.be.withtimebe.global.security.annotation.AuthenticatedMember;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
public class NoticeQueryController {

private final NoticeQueryService noticeQueryService;

@Operation(summary = "공지사항 전체 조회 API by 피우", description = "공지사항 전체 조회 API입니다. (검색어 X)")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(
responseCode = "404",
description = """
- NOTICE404_1 : 해당하는 공지사항 유형을 찾을 수 없습니다."
""")
})
@Parameter(name = "noticeCategory", description = "SYSTEM / SERVICE")
@SwaggerPageable
@GetMapping("/notices")
public DefaultResponse<NoticeResponseDTO.NoticeList> findNoticeList(
@PageableDefault(page = 0, size = 10) Pageable pageable,
@RequestParam String noticeCategory
) {
NoticeRequestDTO.FindNoticeList request = NoticeConverter.toFindNoticeList(pageable, noticeCategory);
Page<Notice> result = noticeQueryService.findNoticeList(request);
NoticeResponseDTO.NoticeList response = NoticeConverter.toNoticeList(result);
return DefaultResponse.ok(response);
}

@Operation(summary = "공지사항 검색어 전체 조회 API by 피우", description = "공지사항 전체 조회 API입니다. (검색어 O)")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(
responseCode = "404",
description = """
- NOTICE404_1 : 해당하는 공지사항 유형을 찾을 수 없습니다."
""")
})
@Parameter(name = "noticeCategory", description = "SYSTEM / SERVICE")
@SwaggerPageable
@GetMapping("/notices/search")
public DefaultResponse<NoticeResponseDTO.NoticeList> findNoticeListByKeyword(
@PageableDefault(page = 0, size = 10) Pageable pageable,
@RequestParam String keyword,
@RequestParam String noticeCategory
) {
NoticeRequestDTO.FindNoticeListByKeyword request = NoticeConverter.toFindNoticeListByKeyword(pageable, keyword, noticeCategory);
Page<Notice> result = noticeQueryService.findNoticeListByKeyword(request);
NoticeResponseDTO.NoticeList response = NoticeConverter.toNoticeList(result);
return DefaultResponse.ok(response);
}

@Operation(summary = "공지사항 상세 조회 API by 피우", description = "공지사항 상세 조회 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(
responseCode = "403",
description = """
- NOTICE403_1 : 삭제된 공지사항을 열람할 Admin 권한이 없습니다.
"""),
@ApiResponse(
responseCode = "404",
description = """
- NOTICE404_2 : 해당하는 공지사항을 찾을 수 없습니다.
""")
})
@GetMapping("/notices/{noticeId}")
public DefaultResponse<NoticeResponseDTO.NoticeDetail> findNoticeDetail(
@PathVariable("noticeId") Long noticeId,
@AuthenticatedMember Member member
) {
NoticeRequestDTO.FindNoticeDetail request = NoticeConverter.toFindNoticeDetail(noticeId, member);
Notice result = noticeQueryService.findNoticeDetail(request);
NoticeResponseDTO.NoticeDetail response = NoticeConverter.toNoticeDetail(result, member);
return DefaultResponse.ok(response);
}

@Operation(summary = "삭제된 공지사항 전체 조회 API Only Admin by 피우", description = "삭제된 공지사항 상세 조회 API입니다. 어드민만 사용 가능합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공입니다."),
@ApiResponse(responseCode = "403",
description = """
- COMMON403 : "Admin 권한이 없음을 의미합니다."
"""),
@ApiResponse(
responseCode = "404",
description = """
- NOTICE404_1 : "해당하는 공지사항 유형을 찾을 수 없습니다."
""")
})
@Parameter(name = "noticeCategory", description = "SYSTEM / SERVICE")
@SwaggerPageable
@GetMapping("/admin/notices/trash")
public DefaultResponse<NoticeResponseDTO.NoticeList> findTrashNoticeList(
@PageableDefault(page = 0, size = 10) Pageable pageable,
@RequestParam String noticeCategory
) {
NoticeRequestDTO.FindNoticeList request = NoticeConverter.toFindNoticeList(pageable, noticeCategory);
Page<Notice> result = noticeQueryService.findTrashNoticeList(request);
NoticeResponseDTO.NoticeList response = NoticeConverter.toNoticeList(result);
return DefaultResponse.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.withtime.be.withtimebe.domain.notice.converter;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.withtime.be.withtimebe.domain.member.entity.Member;
import org.withtime.be.withtimebe.domain.member.entity.enums.Role;
import org.withtime.be.withtimebe.domain.notice.dto.request.NoticeRequestDTO;
import org.withtime.be.withtimebe.domain.notice.dto.response.NoticeResponseDTO;
import org.withtime.be.withtimebe.domain.notice.entity.Notice;
import org.withtime.be.withtimebe.domain.notice.entity.enums.NoticeCategory;
import org.withtime.be.withtimebe.global.error.code.NoticeErrorCode;
import org.withtime.be.withtimebe.global.error.exception.NoticeException;

public class NoticeConverter {

// Request DTO : 전체 조회 (Controller -> Service)
public static NoticeRequestDTO.FindNoticeList toFindNoticeList(Pageable pageable, String type) {

NoticeCategory noticeCategory;

try {
noticeCategory = NoticeCategory.valueOf(type);
} catch (IllegalArgumentException e) {
throw new NoticeException(NoticeErrorCode.NOTICE_CATEGORY_NOT_FOUND);
}

return NoticeRequestDTO.FindNoticeList.builder()
.pageable(pageable)
.noticeCategory(noticeCategory)
.build();
}

// Request DTO : 검색어 전체 조회 (Controller -> Service)
public static NoticeRequestDTO.FindNoticeListByKeyword toFindNoticeListByKeyword(Pageable pageable, String keyword, String type) {

NoticeCategory noticeCategory;

try {
noticeCategory = NoticeCategory.valueOf(type);
} catch (IllegalArgumentException e) {
throw new NoticeException(NoticeErrorCode.NOTICE_CATEGORY_NOT_FOUND);
}

return NoticeRequestDTO.FindNoticeListByKeyword.builder()
.pageable(pageable)
.keyword(keyword)
.noticeCategory(noticeCategory)
.build();
}

// Request : 상세 조회 요청 (Controller -> Service) DTO
public static NoticeRequestDTO.FindNoticeDetail toFindNoticeDetail(Long noticeId, Member member) {

return NoticeRequestDTO.FindNoticeDetail.builder()
.noticeId(noticeId)
.member(member)
.build();
}

// Response DTO : NoticeResponseDTO.NoticeList
public static NoticeResponseDTO.NoticeList toNoticeList(Page<Notice> noticePage) {

List<NoticeResponseDTO.Notice> noticeList = noticePage.getContent().stream()
.map(NoticeConverter::toNotice)
.toList();

return NoticeResponseDTO.NoticeList.builder()
.noticeList(noticeList)
.totalPages(noticePage.getTotalPages())
.currentPage(noticePage.getNumber())
.currentSize(noticePage.getNumberOfElements())
.hasNextPage(noticePage.hasNext())
.build();
}

// Response DTO : NoticeResponseDTO.Notice
public static NoticeResponseDTO.Notice toNotice(Notice notice) {

return NoticeResponseDTO.Notice.builder()
.noticeId(notice.getId())
.title(notice.getTitle())
.isPinned(notice.getIsPinned())
.createdAt(notice.getCreatedAt())
.build();
}

// Response : NoticeDetail(DTO)로 변환
public static NoticeResponseDTO.NoticeDetail toNoticeDetail(Notice notice, Member member) {

boolean hasAdminAuth = member != null && member.getRole().equals(Role.ADMIN);

return NoticeResponseDTO.NoticeDetail.builder()
.noticeId(notice.getId())
.title(notice.getTitle())
.content(notice.getContent())
.isPinned(notice.getIsPinned())
.hasAdminAuth(hasAdminAuth)
.createdAt(notice.getCreatedAt())
.build();
}

public static Notice toNoticeEntity(NoticeRequestDTO.CreateNotice request, Member member) {

return Notice.builder()
.member(member)
.title(request.title())
.content(request.content())
.isPinned(request.isPinned())
.build();
}
}
Loading