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

πŸš€ μ’‹μ•„μš” μš”μ²­ 및 μ·¨μ†Œ κΈ°λŠ₯ μž‘μ„± #55

Merged
merged 14 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 16 additions & 0 deletions mysql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,19 @@ CREATE TABLE posts
FOREIGN KEY (user_id)
REFERENCES users (id)
);

CREATE TABLE likes
(
id BIGINT AUTO_INCREMENT,
user_id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
status TINYINT NOT NULL,
created_at DATETIME(6) NULL,
updated_at DATETIME(6) NULL,
CONSTRAINT posts_pk
PRIMARY KEY (id),
FOREIGN KEY (user_id)
REFERENCES users (id),
FOREIGN KEY (post_id)
REFERENCES posts (id)
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

@Getter
@RequiredArgsConstructor
public class ImageUploadException extends RuntimeException{
public class ImageUploadException extends RuntimeException {

private final String message = "이미지 μ—…λ‘œλ“œ 쀑 μ˜ˆμ™Έκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.backendoori.ootw.like.controller;

import com.backendoori.ootw.like.dto.controller.LikeRequest;
import com.backendoori.ootw.like.dto.controller.LikeResponse;
import com.backendoori.ootw.like.service.LikeService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
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;

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

private final LikeService likeService;

@PostMapping
public ResponseEntity<LikeResponse> pushLike(Authentication authentication,
@Valid @RequestBody LikeRequest requestDto) {
Long userId = (Long) authentication.getPrincipal();
return ResponseEntity.ok(likeService.requestLike(userId, requestDto.postId()));
}

}
58 changes: 58 additions & 0 deletions src/main/java/com/backendoori/ootw/like/domain/Like.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.backendoori.ootw.like.domain;

import com.backendoori.ootw.common.BaseEntity;
import com.backendoori.ootw.post.domain.Post;
import com.backendoori.ootw.user.domain.User;
import io.jsonwebtoken.lang.Assert;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Table(name = "likes")
@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Like extends BaseEntity {

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
private Post post;

@Column(name = "status", columnDefinition = "tinyint")
private Boolean status;

private Like(Long id, User user, Post post, Boolean status) {
Assert.notNull(user);
Assert.notNull(post);
Assert.notNull(status);
this.id = id;
this.user = user;
this.post = post;
this.status = status;
}

public void updateStatus() {
this.status = !status;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.backendoori.ootw.like.dto.controller;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;

public record LikeRequest(
@Positive
@NotNull(message = NULL_MESSAGE)
Long postId
) {

private static final String NULL_MESSAGE = "λ°˜λ“œμ‹œ postId 값이 null μž…λ‹ˆλ‹€.";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.backendoori.ootw.like.dto.controller;

import com.backendoori.ootw.like.domain.Like;

public record LikeResponse(
Long likeId,
Long userId,
Long postId,
boolean status
) {

public static LikeResponse from(Like like) {
return new LikeResponse(
like.getId(),
like.getUser().getId(),
like.getPost().getId(),
like.getStatus());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.backendoori.ootw.like.repository;

import java.util.Optional;
import com.backendoori.ootw.like.domain.Like;
import com.backendoori.ootw.post.domain.Post;
import com.backendoori.ootw.user.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface LikeRepository extends JpaRepository<Like, Long> {

Optional<Like> findByUserAndPost(User user, Post post);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.backendoori.ootw.like.service;

import java.util.NoSuchElementException;
import com.backendoori.ootw.exception.UserNotFoundException;
import com.backendoori.ootw.like.domain.Like;
import com.backendoori.ootw.like.dto.controller.LikeResponse;
import com.backendoori.ootw.like.repository.LikeRepository;
import com.backendoori.ootw.post.domain.Post;
import com.backendoori.ootw.post.repository.PostRepository;
import com.backendoori.ootw.user.domain.User;
import com.backendoori.ootw.user.repository.UserRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class LikeService {

private static final String POST_NOT_FOUND_MESSAGE = "ν•΄λ‹Ή κ²Œμ‹œκΈ€μ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.";
private static final String LIKE_NOT_FOUND_MESSAGE = "μ°ΎμœΌμ‹œλŠ” μ’‹μ•„μš” 정보가 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.";

private final UserRepository userRepository;
private final PostRepository postRepository;
private final LikeRepository likeRepository;

@Transactional
public LikeResponse requestLike(Long userId, Long postId) {
User user = userRepository.findById(userId)
.orElseThrow(UserNotFoundException::new);

Post post = postRepository.findById(postId)
.orElseThrow(() -> new NoSuchElementException(POST_NOT_FOUND_MESSAGE));

likeRepository.findByUserAndPost(user, post).ifPresentOrElse(
Like::updateStatus,
likeNotExist(user, post)
);

Like like = likeRepository.findByUserAndPost(user, post)
.orElseThrow(() -> new NoSuchElementException(LIKE_NOT_FOUND_MESSAGE));

return LikeResponse.from(like);
}

@NotNull
private Runnable likeNotExist(User user, Post post) {
return () -> {
likeRepository.save(
Like.builder()
.user(user)
.post(post)
.status(true)
.build());
};
}

}
Loading
Loading