Skip to content

Commit

Permalink
Merge pull request #27 from Team-baebae/feature/alarm/#24
Browse files Browse the repository at this point in the history
Feature/alarm/#24
  • Loading branch information
tioon authored May 3, 2024
2 parents 1547a90 + 7dfa772 commit 8a3d2fb
Show file tree
Hide file tree
Showing 12 changed files with 607 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.web.baebaeBE.application.notification;

import com.web.baebaeBE.domain.notification.service.NotificationService;
import com.web.baebaeBE.presentation.notification.dto.NotificationResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class NotificationApplication {

private final NotificationService notificationService;


// 특정 멤버의 모든 알람 조회
public NotificationResponse.NotificationListResponse getNotificationsListByMember(Long memberId) {
return notificationService.getNotificationsListByMember(memberId);
}

// 알림 세부정보 조회
public NotificationResponse.NotificationContentResponse getNotificationById(Long notificationId) {
return notificationService.getNotificationById(notificationId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.web.baebaeBE.domain.notification.exception;

import com.web.baebaeBE.global.error.ErrorCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;

@Getter
@RequiredArgsConstructor
public enum NotificationError implements ErrorCode {


NOT_EXIST_MEMBER(HttpStatus.NOT_FOUND, "A-001", "존재하지 않는 알림입니다.");

private final HttpStatus httpStatus;
private final String errorCode;
private final String message;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.web.baebaeBE.domain.notification.service;

import com.web.baebaeBE.domain.member.exception.MemberError;
import com.web.baebaeBE.global.error.exception.BusinessException;
import com.web.baebaeBE.infra.notification.entity.Notification;
import com.web.baebaeBE.infra.notification.repository.NotificationRepository;
import com.web.baebaeBE.infra.member.entity.Member;
import com.web.baebaeBE.infra.member.repository.MemberRepository;
import com.web.baebaeBE.presentation.notification.dto.NotificationRequest;
import com.web.baebaeBE.presentation.notification.dto.NotificationResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
public class NotificationService {

private final NotificationRepository notificationRepository;
private final MemberRepository memberRepository;

// 알림 생성
public Notification createNotification(NotificationRequest.create createNotificationDto) {
Member member = memberRepository.findById(createNotificationDto.getMemberId())
.orElseThrow(() -> new BusinessException(MemberError.NOT_EXIST_MEMBER));

return notificationRepository.save(Notification.builder()
.member(member)
.notificationContent(createNotificationDto.getNotificationContent())
.questionContent(createNotificationDto.getQuestionContent())
.build());
}


// 특정 멤버의 모든 알람 조회
public NotificationResponse.NotificationListResponse getNotificationsListByMember(Long memberId) {
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new BusinessException(MemberError.NOT_EXIST_MEMBER));

List<Notification> notificationList = notificationRepository.findByMemberOrderByNotificationTimeDesc(member);

return NotificationResponse.NotificationContentResponse.ListOf(notificationList);
}

// 알림 세부정보 조회
public NotificationResponse.NotificationContentResponse getNotificationById(Long notificationId) {
Member member = memberRepository.findById(notificationId)
.orElseThrow(() -> new BusinessException(MemberError.NOT_EXIST_MEMBER));


return NotificationResponse.NotificationContentResponse
.of(notificationRepository.findById(notificationId).get());
}


// 알람 삭제
public void deleteNotification(Long notificationId) {
notificationRepository.deleteById(notificationId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.web.baebaeBE.infra.notification.entity;


import com.fasterxml.jackson.annotation.JsonFormat;
import com.web.baebaeBE.infra.member.entity.Member;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import java.time.LocalDateTime;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Table(name = "notification")
public class Notification {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "notification_id", nullable = false)
private Long id;

@ManyToOne
@JoinColumn(name = "member_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Member member;

@Column(name = "notification_content", columnDefinition = "TEXT", nullable = false)
private String notificationContent;

@Column(name = "question_content", columnDefinition = "TEXT")
private String questionContent;

@Column(name = "notification_time", nullable = false)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime notificationTime;

// 엔티티가 데이터베이스에 처음 저장될때 자동으로 현재 시간 설정
@PrePersist
protected void onCreate() {
notificationTime = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.web.baebaeBE.infra.notification.repository;

import com.web.baebaeBE.infra.notification.entity.Notification;
import com.web.baebaeBE.infra.member.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface NotificationRepository extends JpaRepository<Notification, Long> {
List<Notification> findByMemberOrderByNotificationTimeDesc(Member member);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class Member implements UserDetails {
@Column(name = "refresh_token")
private String refreshToken;

@Column(name = "token_expiration_time")
private LocalDateTime tokenExpirationTime;


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.web.baebaeBE.presentation.notification;

import com.web.baebaeBE.application.notification.NotificationApplication;
import com.web.baebaeBE.presentation.notification.api.NotificationApi;
import com.web.baebaeBE.presentation.notification.dto.NotificationResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
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.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/notifications") // 모든 경로가 "/api/notifications"로 시작합니다.
public class NotificationController implements NotificationApi {

private final NotificationApplication notificationApplication;


// 특정 멤버의 모든 알람 조회
@GetMapping("/member/{memberId}")
public ResponseEntity<NotificationResponse.NotificationListResponse> getNotificationsListByMember(@PathVariable Long memberId) {
NotificationResponse.NotificationListResponse notifications = notificationApplication.getNotificationsListByMember(memberId);

return ResponseEntity.ok(notifications);
}

// 알람 세부정보 조회
@GetMapping("/{notificationId}")
public ResponseEntity<NotificationResponse.NotificationContentResponse> getNotificationById(@PathVariable Long notificationId) {
NotificationResponse.NotificationContentResponse notification = notificationApplication.getNotificationById(notificationId);

return ResponseEntity.ok(notification);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.web.baebaeBE.presentation.notification.api;

import com.web.baebaeBE.presentation.notification.dto.NotificationResponse;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "Notification", description = "알림 조회 API")
@RequestMapping("/api/notifications")
public interface NotificationApi {

@Operation(
summary = "유저의 모든 알림 조회",
description = "지정된 멤버 ID에 대한 모든 알림을 조회합니다."
)
@Parameter(
in = ParameterIn.HEADER,
name = "Authorization", required = true,
schema = @Schema(type = "string"),
description = "Bearer [Access 토큰]")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(
implementation = NotificationResponse.NotificationListResponse.class
))
),
@ApiResponse(responseCode = "401", description = "토큰 인증 실패",
content = @Content(mediaType = "application/json",
examples = @ExampleObject(value = "{\n" +
" \"errorCode\": \"M-003\",\n" +
" \"message\": \"해당 토큰은 유효한 토큰이 아닙니다.\"\n" +
"}"))
),
@ApiResponse(responseCode = "404", description = "존재하지 않는 회원",
content = @Content(mediaType = "application/json",
examples = @ExampleObject(value = "{\n" +
" \"errorCode\": \"M-002\",\n" +
" \"message\": \"존재하지 않는 회원입니다.\"\n" +
"}"))
)
})
ResponseEntity<NotificationResponse.NotificationListResponse> getNotificationsListByMember(@Parameter(description = "멤버의 ID", required = true) @PathVariable Long memberId);

@Operation(
summary = "알림 세부정보 조회",
description = "지정된 알림 ID로 알림 세부정보를 조회합니다.",
security = @SecurityRequirement(name = "bearerAuth")
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = NotificationResponse.NotificationContentResponse.class))
),
@ApiResponse(responseCode = "401", description = "토큰 인증 실패",
content = @Content(mediaType = "application/json",
examples = @ExampleObject(value = "{\n" +
" \"errorCode\": \"M-003\",\n" +
" \"message\": \"해당 토큰은 유효한 토큰이 아닙니다.\"\n" +
"}"))
)
})
ResponseEntity<NotificationResponse.NotificationContentResponse> getNotificationById(@Parameter(description = "알림의 ID", required = true) @PathVariable Long notificationId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.web.baebaeBE.presentation.notification.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;


public class NotificationRequest {

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class create{
private Long memberId;
private String notificationContent;
private String questionContent;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.web.baebaeBE.presentation.notification.dto;

import com.web.baebaeBE.infra.notification.entity.Notification;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;


public class NotificationResponse {

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class NotificationContentResponse {

@Schema(example = "1")
private Long notificationId;
@Schema(example = "배승우님이 질문을 남기셨습니다! 확인해보세요")
private String notificationContent;
@Schema(example = "가은아! 넌 무슨색상을 좋아해?")
private String questionContent;
@Schema(type = "string", example = "2024-05-02 07:10:48")
private LocalDateTime notificationTime;

public static NotificationResponse.NotificationContentResponse of(Notification notification) {
return NotificationContentResponse.builder()
.notificationId(notification.getId())
.notificationContent(notification.getNotificationContent())
.questionContent(notification.getQuestionContent())
.notificationTime(notification.getNotificationTime())
.build();
}

public static NotificationListResponse ListOf(List<Notification> notificationList) {
List<NotificationResponse.NotificationContentResponse> responseList = notificationList.stream()
.map(notification -> NotificationResponse.NotificationContentResponse.builder()
.notificationId(notification.getId())
.notificationContent(notification.getNotificationContent())
.questionContent(notification.getQuestionContent())
.notificationTime(notification.getNotificationTime())
.build())
.collect(Collectors.toList());

return NotificationListResponse.builder()
.notificationList(responseList)
.build();
}

}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class NotificationListResponse{
private List<NotificationContentResponse> notificationList;


}
}
Loading

0 comments on commit 8a3d2fb

Please sign in to comment.