#24 simple sns: 알림기능 api

This commit is contained in:
haerong22
2022-11-25 03:39:44 +09:00
parent d314680151
commit 14dda18ecd
11 changed files with 215 additions and 16 deletions

View File

@@ -23,6 +23,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.vladmihalcea:hibernate-types-52:2.17.3'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'

View File

@@ -2,16 +2,17 @@ package com.example.sns.controller;
import com.example.sns.controller.request.UserJoinRequest;
import com.example.sns.controller.request.UserLoginRequest;
import com.example.sns.controller.response.AlarmResponse;
import com.example.sns.controller.response.Response;
import com.example.sns.controller.response.UserJoinResponse;
import com.example.sns.controller.response.UserLoginResponse;
import com.example.sns.model.User;
import com.example.sns.service.UserService;
import lombok.RequiredArgsConstructor;
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.RestController;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/users")
@@ -32,4 +33,9 @@ public class UserController {
String token = userService.login(request.getName(), request.getPassword());
return Response.success(new UserLoginResponse(token));
}
@GetMapping("/alarm")
public Response<Page<AlarmResponse>> alarm(Pageable pageable, Authentication authentication) {
return Response.success(userService.alarmList(authentication.getName(), pageable).map(AlarmResponse::fromAlarm));
}
}

View File

@@ -0,0 +1,34 @@
package com.example.sns.controller.response;
import com.example.sns.model.Alarm;
import com.example.sns.model.AlarmArgs;
import com.example.sns.model.AlarmType;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.sql.Timestamp;
@Data
@AllArgsConstructor
public class AlarmResponse {
private Integer id;
private AlarmType alarmType;
private AlarmArgs args;
private String text;
private Timestamp registeredAt;
private Timestamp updateAt;
private Timestamp deleteAt;
public static AlarmResponse fromAlarm(Alarm alarm) {
return new AlarmResponse(
alarm.getId(),
alarm.getAlarmType(),
alarm.getArgs(),
alarm.getAlarmType().getAlarmText(),
alarm.getRegisteredAt(),
alarm.getUpdatedAt(),
alarm.getDeletedAt()
);
}
}

View File

@@ -0,0 +1,33 @@
package com.example.sns.model;
import com.example.sns.model.entity.AlarmEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.sql.Timestamp;
@Getter
@AllArgsConstructor
public class Alarm {
private Integer id;
private User user;
private AlarmType alarmType;
private AlarmArgs args;
private Timestamp registeredAt;
private Timestamp updatedAt;
private Timestamp deletedAt;
public static Alarm fromEntity(AlarmEntity entity) {
return new Alarm(
entity.getId(),
User.fromEntity(entity.getUser()),
entity.getAlarmType(),
entity.getArgs(),
entity.getRegisteredAt(),
entity.getUpdatedAt(),
entity.getDeletedAt()
);
}
}

View File

@@ -0,0 +1,12 @@
package com.example.sns.model;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class AlarmArgs {
private Integer fromUserId;
private Integer targetId;
}

View File

@@ -0,0 +1,14 @@
package com.example.sns.model;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum AlarmType {
NEW_COMMENT_ON_POST("new comment!"),
NEW_LIKE_ON_POST("new like"),
;
private final String alarmText;
}

View File

@@ -0,0 +1,66 @@
package com.example.sns.model.entity;
import com.example.sns.model.AlarmArgs;
import com.example.sns.model.AlarmType;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.Where;
import javax.persistence.*;
import java.sql.Timestamp;
import java.time.Instant;
@Entity
@Table(name = "alarms", indexes = {
@Index(name = "user_id_idx", columnList = "user_id")
})
@Getter
@Setter
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@SQLDelete(sql = "UPDATE alarms SET deleted_at = NOW() where id=?")
@Where(clause = "deleted_at IS NULL")
public class AlarmEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne
@JoinColumn(name = "user_id")
private UserEntity user;
@Enumerated(EnumType.STRING)
private AlarmType alarmType;
@Type(type = "jsonb")
@Column(columnDefinition = "json")
private AlarmArgs args;
private Timestamp registeredAt;
private Timestamp updatedAt;
@Column(name = "deleted_at")
private Timestamp deletedAt;
@PrePersist
void registeredAt() {
this.registeredAt = Timestamp.from(Instant.now());
}
@PreUpdate
void updatedAt() {
this.updatedAt = Timestamp.from(Instant.now());
}
public static AlarmEntity of(UserEntity userEntity, AlarmType alarmType, AlarmArgs args) {
AlarmEntity entity = new AlarmEntity();
entity.setUser(userEntity);
entity.setAlarmType(alarmType);
entity.setArgs(args);
return entity;
}
}

View File

@@ -0,0 +1,14 @@
package com.example.sns.repository;
import com.example.sns.model.entity.AlarmEntity;
import com.example.sns.model.entity.UserEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AlarmEntityRepository extends JpaRepository<AlarmEntity, Integer> {
Page<AlarmEntity> findAllByUser(UserEntity user, Pageable pageable);
}

View File

@@ -1,16 +1,12 @@
package com.example.sns.service;
import com.example.sns.exception.SnsApplicationException;
import com.example.sns.model.AlarmArgs;
import com.example.sns.model.AlarmType;
import com.example.sns.model.Comment;
import com.example.sns.model.Post;
import com.example.sns.model.entity.CommentEntity;
import com.example.sns.model.entity.LikeEntity;
import com.example.sns.model.entity.PostEntity;
import com.example.sns.model.entity.UserEntity;
import com.example.sns.repository.CommentEntityRepository;
import com.example.sns.repository.LikeEntityRepository;
import com.example.sns.repository.PostEntityRepository;
import com.example.sns.repository.UserEntityRepository;
import com.example.sns.model.entity.*;
import com.example.sns.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -27,6 +23,7 @@ public class PostService {
private final UserEntityRepository userEntityRepository;
private final LikeEntityRepository likeEntityRepository;
private final CommentEntityRepository commentEntityRepository;
private final AlarmEntityRepository alarmEntityRepository;
@Transactional
public void create(String title, String body, String username) {
@@ -94,6 +91,13 @@ public class PostService {
// save like
likeEntityRepository.save(LikeEntity.of(userEntity, postEntity));
alarmEntityRepository.save(AlarmEntity.of(
postEntity.getUser(),
AlarmType.NEW_LIKE_ON_POST,
new AlarmArgs(userEntity.getId(), postEntity.getId())
)
);
}
public int likeCount(Integer postId) {
@@ -109,6 +113,13 @@ public class PostService {
UserEntity userEntity = getUserEntityOrException(username);
commentEntityRepository.save(CommentEntity.of(userEntity, postEntity, comment));
alarmEntityRepository.save(AlarmEntity.of(
postEntity.getUser(),
AlarmType.NEW_COMMENT_ON_POST,
new AlarmArgs(userEntity.getId(), postEntity.getId())
)
);
}
public Page<Comment> getComments(Integer postId, Pageable pageable) {

View File

@@ -1,9 +1,10 @@
package com.example.sns.service;
import com.example.sns.exception.ErrorCode;
import com.example.sns.exception.SnsApplicationException;
import com.example.sns.model.Alarm;
import com.example.sns.model.User;
import com.example.sns.model.entity.UserEntity;
import com.example.sns.repository.AlarmEntityRepository;
import com.example.sns.repository.UserEntityRepository;
import com.example.sns.util.JwtTokenUtils;
import lombok.RequiredArgsConstructor;
@@ -21,6 +22,7 @@ import static com.example.sns.exception.ErrorCode.*;
public class UserService {
private final UserEntityRepository userEntityRepository;
private final AlarmEntityRepository alarmEntityRepository;
private final BCryptPasswordEncoder encoder;
@Value("${jwt.secret-key}")
@@ -67,7 +69,12 @@ public class UserService {
return JwtTokenUtils.generateToken(username, secretKey, expiredTimeMs);
}
public Page<Void> alarmList(String username, Pageable pageable) {
return Page.empty();
public Page<Alarm> alarmList(String username, Pageable pageable) {
UserEntity userEntity = userEntityRepository.findByUsername(username)
.orElseThrow(
() -> new SnsApplicationException(USER_NOT_FOUND, String.format("%s not founded", username))
);
return alarmEntityRepository.findAllByUser(userEntity, pageable).map(Alarm::fromEntity);
}
}

View File

@@ -132,7 +132,7 @@ public class UserControllerTest {
mockMvc.perform(get("/api/v1/users/alarm")
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
.andExpect(status().isUnauthorized());
}