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] 알림 어드민 API 개발 #173

Merged
merged 8 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public enum ExceptionMessage {
END_LECTURE("이미 종료된 세션입니다."),
NO_SUB_LECTURE_EQUAL_ROUND("해당 라운드와 일치하는 출석 세션이 없습니다."),
FAULT_DATE_FORMATTER("잘못된 날짜 형식입니다."),
DUPLICATED_MEMBER("이미 존재하는 회원입니다.");
DUPLICATED_MEMBER("이미 존재하는 회원입니다."),
INVALID_ALARM("존재하지 않는 알림입니다.");

private final String name;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ public enum ResponseMessage {
SUCCESS_GET_LECTURE("세션 상세 조회 성공"),
SUCCESS_START_ATTENDANCE("출석 시작 성공"),
SUCCESS_GET_MEMBERS("유저 리스트 조회 성공"),
SUCCESS_DELETE_LECTURE("세션 삭제 성공");
SUCCESS_DELETE_LECTURE("세션 삭제 성공"),

/** alarm **/
SUCCESS_CREATE_ALARM("알림 생성 성공"),
SUCCESS_GET_ALARMS("알림 리스트 조회 성공"),
SUCCESS_GET_ALARM("알림 상세 조회 성공"),
SUCCESS_DELETE_ALARM("알림 삭제 성공")
;

private final String message;
}
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,
Copy link
Member

Choose a reason for hiding this comment

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

현재기수는 fe에서 관리하는거죠?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

네! 세션 생성에서도 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
Expand Up @@ -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;

Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

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

List 변경이 가능할까요:!

) {
public Alarm toEntity() {
Copy link
Member

Choose a reason for hiding this comment

The 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();
}
}
}
14 changes: 10 additions & 4 deletions src/main/java/org/sopt/makers/operation/entity/alarm/Alarm.java
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.*;

Expand Down Expand Up @@ -43,7 +44,7 @@ public class Alarm extends BaseEntity {

private String link;

private boolean isActive;
private Boolean isActive;

@Enumerated(value = STRING)
private Part part;
Expand All @@ -64,8 +65,13 @@ public Alarm(AlarmRequestDTO requestDTO) {
this.title = requestDTO.title();
Copy link
Member

Choose a reason for hiding this comment

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

코드리뷰에 잡히지 않아서 커서를 여기다 두었는데,
혹시 이부분 List으로 변경할수 있을까요?! 알림서버에서 스트링값으로 받고 있어서!(dynamoDB)
늦게 이야기해서 죄송합니다 ㅠㅠ

@Column(columnDefinition = "TEXT")
	@Convert(converter = LongListConverter.class)
	private List<Long> targetList;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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;
}
}
15 changes: 15 additions & 0 deletions src/main/java/org/sopt/makers/operation/service/AlarmService.java
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()));
}
}