-
Notifications
You must be signed in to change notification settings - Fork 1
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] 알림 어드민 API 개발 #173
[FEAT] 알림 어드민 API 개발 #173
Changes from 7 commits
3ea3b78
5bf894f
ca2a9fa
5da2150
0e6fb74
52221b4
62cafb7
6eff718
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.sopt.makers.operation.controller.web; | ||
|
||
import static org.sopt.makers.operation.common.ApiResponse.*; | ||
import static org.sopt.makers.operation.common.ResponseMessage.*; | ||
|
||
import java.net.URI; | ||
|
||
import org.sopt.makers.operation.common.ApiResponse; | ||
import org.sopt.makers.operation.dto.alarm.AlarmRequestDTO; | ||
import org.sopt.makers.operation.entity.Part; | ||
import org.sopt.makers.operation.entity.alarm.Status; | ||
import org.sopt.makers.operation.service.AlarmService; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.http.ResponseEntity; | ||
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; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder; | ||
|
||
import io.swagger.annotations.ApiOperation; | ||
import lombok.*; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/alarms") | ||
public class AlarmController { | ||
private final AlarmService alarmService; | ||
|
||
@ApiOperation("알림 생성") | ||
@PostMapping | ||
public ResponseEntity<ApiResponse> createAlarm(@RequestBody AlarmRequestDTO requestDTO) { | ||
val alarmId = alarmService.createAlarm(requestDTO); | ||
return ResponseEntity | ||
.created(getURI(alarmId)) | ||
.body(success(SUCCESS_CREATE_ALARM.getMessage(), alarmId)); | ||
} | ||
|
||
@ApiOperation("알림 리스트 조회") | ||
@GetMapping | ||
public ResponseEntity<ApiResponse> getAlarms( | ||
@RequestParam(required = false) Integer generation, | ||
@RequestParam(required = false) Part part, | ||
@RequestParam(required = false) Status status, | ||
Pageable pageable | ||
) { | ||
val response = alarmService.getAlarms(generation, part, status, pageable); | ||
return ResponseEntity.ok(success(SUCCESS_GET_ALARMS.getMessage(), response)); | ||
} | ||
|
||
@ApiOperation("알림 상세 조회") | ||
@GetMapping("/{alarmId}") | ||
public ResponseEntity<ApiResponse> getAlarm(@PathVariable Long alarmId) { | ||
val response = alarmService.getAlarm(alarmId); | ||
return ResponseEntity.ok(success(SUCCESS_GET_ALARM.getMessage(), response)); | ||
} | ||
|
||
@ApiOperation("알림 삭제") | ||
@DeleteMapping("/{alarmId}") | ||
public ResponseEntity<ApiResponse> deleteAlarm(@PathVariable Long alarmId) { | ||
alarmService.deleteAlarm(alarmId); | ||
return ResponseEntity.ok(success(SUCCESS_DELETE_ALARM.getMessage())); | ||
} | ||
|
||
private URI getURI(Long alarmId) { | ||
return ServletUriComponentsBuilder | ||
.fromCurrentRequest() | ||
.path("/{alarmId}") | ||
.buildAndExpand(alarmId) | ||
.toUri(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
import java.util.List; | ||
|
||
import org.sopt.makers.operation.entity.Part; | ||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
import org.sopt.makers.operation.entity.alarm.Attribute; | ||
import org.sopt.makers.operation.entity.alarm.Status; | ||
|
||
|
@@ -12,9 +13,11 @@ public record AlarmRequestDTO( | |
String title, | ||
String content, | ||
String link, | ||
boolean isActive, | ||
Boolean isActive, | ||
Part part, | ||
List<Long> targetList, | ||
Status status | ||
List<Long> targetList | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. List 변경이 가능할까요:! |
||
) { | ||
public Alarm toEntity() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 이거 새롭네요..! 나중에 다른거도 이렇게 하면 좋겠네요 좋아요! |
||
return new Alarm(this); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.sopt.makers.operation.dto.alarm; | ||
|
||
import static java.util.Objects.*; | ||
|
||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
|
||
import lombok.Builder; | ||
|
||
@Builder | ||
public record AlarmResponseDTO( | ||
String attribute, | ||
String part, | ||
Boolean isActive, | ||
String title, | ||
String content, | ||
String link, | ||
String createdAt, | ||
String sendAt | ||
) { | ||
public static AlarmResponseDTO of(Alarm alarm) { | ||
return AlarmResponseDTO.builder() | ||
.attribute(alarm.getAttribute().getName()) | ||
.part(alarm.getPart().getName()) | ||
.isActive(alarm.getIsActive()) | ||
.title(alarm.getTitle()) | ||
.content(alarm.getContent()) | ||
.link(alarm.getLink()) | ||
.createdAt(alarm.getCreatedDate().toString()) | ||
.sendAt(nonNull(alarm.getSendAt()) ? alarm.getSendAt().toString() : null) | ||
.build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.sopt.makers.operation.dto.alarm; | ||
|
||
import static java.util.Objects.*; | ||
|
||
import java.util.List; | ||
|
||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
|
||
import lombok.Builder; | ||
|
||
public record AlarmsResponseDTO( | ||
List<AlarmVO> alarms | ||
) { | ||
public static AlarmsResponseDTO of(List<Alarm> alarms) { | ||
return new AlarmsResponseDTO(alarms.stream().map(AlarmVO::of).toList()); | ||
} | ||
|
||
@Builder | ||
record AlarmVO( | ||
Long alarmId, | ||
String part, | ||
String attribute, | ||
String title, | ||
String content, | ||
String sendAt, | ||
String status | ||
) { | ||
static AlarmVO of(Alarm alarm) { | ||
return AlarmVO.builder() | ||
.alarmId(alarm.getId()) | ||
.part(nonNull(alarm.getPart()) ? alarm.getPart().getName() : null) | ||
.attribute(alarm.getAttribute().getName()) | ||
.title(alarm.getTitle()) | ||
.content(alarm.getContent()) | ||
.sendAt(nonNull(alarm.getSendAt()) ? alarm.getSendAt().toString() : null) | ||
.status(alarm.getStatus().getName()) | ||
.build(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
package org.sopt.makers.operation.entity.alarm; | ||
|
||
import static java.util.Objects.*; | ||
import static javax.persistence.EnumType.*; | ||
import static javax.persistence.GenerationType.*; | ||
|
||
|
@@ -43,7 +44,7 @@ public class Alarm extends BaseEntity { | |
|
||
private String link; | ||
|
||
private boolean isActive; | ||
private Boolean isActive; | ||
|
||
@Enumerated(value = STRING) | ||
private Part part; | ||
|
@@ -64,8 +65,13 @@ public Alarm(AlarmRequestDTO requestDTO) { | |
this.title = requestDTO.title(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드리뷰에 잡히지 않아서 커서를 여기다 두었는데,
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. String 타입의 리스트를 말하는거죠?? |
||
this.content = requestDTO.content(); | ||
this.link = requestDTO.link(); | ||
this.isActive = requestDTO.isActive(); | ||
this.part = requestDTO.part(); | ||
this.targetList = requestDTO.targetList(); | ||
if (nonNull(requestDTO.isActive()) && nonNull(requestDTO.part())) { | ||
this.isActive = requestDTO.isActive(); | ||
this.part = requestDTO.part(); | ||
} | ||
if (nonNull(requestDTO.targetList())) { | ||
this.targetList = requestDTO.targetList(); | ||
} | ||
this.status = Status.BEFORE; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.sopt.makers.operation.repository.alarm; | ||
|
||
import java.util.List; | ||
|
||
import org.sopt.makers.operation.entity.Part; | ||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
import org.sopt.makers.operation.entity.alarm.Status; | ||
import org.springframework.data.domain.Pageable; | ||
|
||
public interface AlarmCustomRepository { | ||
List<Alarm> getAlarms(Integer generation, Part part, Status status, Pageable pageable); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.sopt.makers.operation.repository.alarm; | ||
|
||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface AlarmRepository extends JpaRepository<Alarm, Long>, AlarmCustomRepository { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package org.sopt.makers.operation.repository.alarm; | ||
|
||
import static java.util.Objects.*; | ||
import static org.sopt.makers.operation.entity.Part.*; | ||
import static org.sopt.makers.operation.entity.alarm.QAlarm.*; | ||
|
||
import java.util.List; | ||
|
||
import org.sopt.makers.operation.entity.Part; | ||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
import org.sopt.makers.operation.entity.alarm.Status; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import com.querydsl.core.types.dsl.BooleanExpression; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class AlarmRepositoryImpl implements AlarmCustomRepository { | ||
private final JPAQueryFactory queryFactory; | ||
|
||
@Override | ||
public List<Alarm> getAlarms(Integer generation, Part part, Status status, Pageable pageable) { | ||
return queryFactory | ||
.selectFrom(alarm) | ||
.where( | ||
generationEq(generation), | ||
partEq(part), | ||
statusEq(status) | ||
) | ||
.orderBy(alarm.createdDate.desc()) | ||
.offset(pageable.getOffset()) | ||
.limit(pageable.getPageSize()) | ||
.fetch(); | ||
} | ||
|
||
private BooleanExpression generationEq(Integer generation) { | ||
return nonNull(generation) ? alarm.generation.eq(generation) : null; | ||
} | ||
|
||
private BooleanExpression partEq(Part part) { | ||
return (nonNull(part) && !part.equals(ALL)) ? alarm.part.eq(part) : null; | ||
} | ||
|
||
private BooleanExpression statusEq(Status status) { | ||
return nonNull(status) ? alarm.status.eq(status) : null; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.sopt.makers.operation.service; | ||
|
||
import org.sopt.makers.operation.dto.alarm.AlarmRequestDTO; | ||
import org.sopt.makers.operation.dto.alarm.AlarmResponseDTO; | ||
import org.sopt.makers.operation.dto.alarm.AlarmsResponseDTO; | ||
import org.sopt.makers.operation.entity.Part; | ||
import org.sopt.makers.operation.entity.alarm.Status; | ||
import org.springframework.data.domain.Pageable; | ||
|
||
public interface AlarmService { | ||
Long createAlarm(AlarmRequestDTO requestDTO); | ||
AlarmsResponseDTO getAlarms(Integer generation, Part part, Status status, Pageable pageable); | ||
AlarmResponseDTO getAlarm(Long alarmId); | ||
void deleteAlarm(Long alarmId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package org.sopt.makers.operation.service; | ||
|
||
import static org.sopt.makers.operation.common.ExceptionMessage.*; | ||
|
||
import javax.persistence.EntityNotFoundException; | ||
|
||
import org.sopt.makers.operation.dto.alarm.AlarmRequestDTO; | ||
import org.sopt.makers.operation.dto.alarm.AlarmResponseDTO; | ||
import org.sopt.makers.operation.dto.alarm.AlarmsResponseDTO; | ||
import org.sopt.makers.operation.entity.Part; | ||
import org.sopt.makers.operation.entity.alarm.Alarm; | ||
import org.sopt.makers.operation.entity.alarm.Status; | ||
import org.sopt.makers.operation.repository.alarm.AlarmRepository; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import lombok.*; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AlarmServiceImpl implements AlarmService { | ||
private final AlarmRepository alarmRepository; | ||
|
||
@Override | ||
@Transactional | ||
public Long createAlarm(AlarmRequestDTO requestDTO) { | ||
val alarmEntity = requestDTO.toEntity(); | ||
val savedAlarm = alarmRepository.save(alarmEntity); | ||
return savedAlarm.getId(); | ||
} | ||
|
||
@Override | ||
public AlarmsResponseDTO getAlarms(Integer generation, Part part, Status status, Pageable pageable) { | ||
val alarms = alarmRepository.getAlarms(generation, part, status, pageable); | ||
return AlarmsResponseDTO.of(alarms); | ||
} | ||
|
||
@Override | ||
public AlarmResponseDTO getAlarm(Long alarmId) { | ||
val alarm = findAlarm(alarmId); | ||
return AlarmResponseDTO.of(alarm); | ||
} | ||
|
||
@Override | ||
@Transactional | ||
public void deleteAlarm(Long alarmId) { | ||
val alarm = findAlarm(alarmId); | ||
alarmRepository.delete(alarm); | ||
} | ||
|
||
private Alarm findAlarm(Long alarmId) { | ||
return alarmRepository.findById(alarmId) | ||
.orElseThrow(() -> new EntityNotFoundException(INVALID_ALARM.getName())); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재기수는 fe에서 관리하는거죠?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네! 세션 생성에서도 generation 값을 받고 있어서 통일되게 작성했어요!