Skip to content

Commit

Permalink
IP 기반 좋아요 기능 구현
Browse files Browse the repository at this point in the history
IP 기반 좋아요 기능 구현
  • Loading branch information
xGreenNarae authored Oct 31, 2023
2 parents 21809a8 + 4889fac commit a8a49d7
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,12 @@ public PetVideo(String videoUrl, Pet pet) {
public void setPet(final Pet pet) {
this.pet = pet;
}

public void updateLikeCount() {
this.likeCount++;
}

public void deleteLikeCount() {
this.likeCount--;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.daggle.animory.domain.shortform.controller;

import com.daggle.animory.common.Response;
import com.daggle.animory.domain.shortform.ShortFormService;
import com.daggle.animory.domain.shortform.service.ShortFormService;
import com.daggle.animory.domain.shortform.dto.request.ShortFormSearchCondition;
import com.daggle.animory.domain.shortform.dto.response.CategoryShortFormPage;
import com.daggle.animory.domain.shortform.dto.response.HomeShortFormPage;
import com.daggle.animory.domain.shortform.service.PetVideoLikeService;
import javax.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
Expand All @@ -21,14 +26,15 @@
public class ShortFormController implements ShortFormControllerApi {

private final ShortFormService shortFormService;

private final PetVideoLikeService petVideoLikeService;
/**
* 다양한 검색 조건 변화에 대응할 수 있는 목적으로 사용할 숏폼 영상 조회 API 입니다.
*/
@Override
@GetMapping("/short-forms")
public Response<CategoryShortFormPage> getShortForms(@ModelAttribute @Valid final ShortFormSearchCondition searchCondition,
@PageableDefault final Pageable pageable) {
public Response<CategoryShortFormPage> getShortForms(
@ModelAttribute @Valid final ShortFormSearchCondition searchCondition,
@PageableDefault final Pageable pageable) {
return Response.success(shortFormService.getCategoryShortFormPage(searchCondition, pageable));
}

Expand All @@ -40,4 +46,17 @@ public Response<HomeShortFormPage> getHomeShortForms(@PageableDefault final Page
return Response.success(shortFormService.getHomeShortFormPage(pageable));
}

@PostMapping("/like/{petVideoId}")
public Response<Void> increasePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId) {
String IPAddress = httpServletRequest.getRemoteAddr();
petVideoLikeService.updatePetVideoLikeCount(IPAddress, petVideoId);
return Response.success();
}

@DeleteMapping("/like/{petVideoId}")
public Response<Void> deletePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId) {
String IPAddress = httpServletRequest.getRemoteAddr();
petVideoLikeService.deletePetVideoLikeCount(IPAddress, petVideoId);
return Response.success();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.servlet.http.HttpServletRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.validation.Valid;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

@Tag(
name = "숏폼 비디오 API",
Expand Down Expand Up @@ -87,4 +91,9 @@ Response<CategoryShortFormPage> getShortForms(@Parameter(hidden = true)
@GetMapping("/short-forms/home")
Response<HomeShortFormPage> getHomeShortForms(@Parameter(hidden = true) @PageableDefault Pageable pageable);

@PostMapping("/like/{petVideoId}")
Response<Void> increasePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId) ;

@DeleteMapping("/like/{petVideoId}")
Response<Void> deletePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.daggle.animory.domain.shortform.entity;

import com.daggle.animory.common.entity.BaseEntity;
import com.daggle.animory.domain.pet.entity.PetVideo;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@Table(name = "pet_video_like")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PetVideoLike extends BaseEntity {

@Id
@GeneratedValue
private Integer id;

@NotNull
private String ipAddress;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pet_video_id")
private PetVideo petVideo;

@Builder
public PetVideoLike(final String ipAddress, final PetVideo petVideo) {
this.ipAddress = ipAddress;
this.petVideo = petVideo;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.daggle.animory.domain.shortform.exception;

public class AlreadyLikedPetVideo extends RuntimeException {
@Override
public String getMessage() {
return ShortFormExceptionMessage.ALREADY_LIKED_PET_VIDEO.getMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.daggle.animory.domain.shortform.exception;

public class NotLikedPetVideo extends RuntimeException {
@Override
public String getMessage() {
return ShortFormExceptionMessage.NOT_LIKED_PET_VIDEO.getMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.daggle.animory.domain.shortform.exception;

public enum ShortFormExceptionMessage {
SHORT_FORM_NOT_FOUND("해당하는 숏폼이 존재하지 않습니다."),
ALREADY_LIKED_PET_VIDEO("이미 좋아요를 누른 영상입니다."),
NOT_LIKED_PET_VIDEO("좋아요를 누르지 않은 영상입니다.");
private final String message;

ShortFormExceptionMessage(String message) {
this.message = message;
}

public String getMessage() {
return message;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.daggle.animory.domain.shortform.exception;

public class ShortFormNotFound extends RuntimeException {
@Override
public String getMessage() {
return ShortFormExceptionMessage.SHORT_FORM_NOT_FOUND.getMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.daggle.animory.domain.shortform.repository;

import com.daggle.animory.domain.shortform.entity.PetVideoLike;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PetVideoLikeRepository extends JpaRepository<PetVideoLike, Integer> {

boolean existsByIpAddressAndPetVideoId(String ipAddress, Integer petVideoId);

void deleteByIpAddressAndPetVideoId(String ipAddress, Integer petVideoId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.daggle.animory.domain.shortform.service;

import com.daggle.animory.domain.pet.entity.PetVideo;
import com.daggle.animory.domain.shortform.entity.PetVideoLike;
import com.daggle.animory.domain.shortform.exception.AlreadyLikedPetVideo;
import com.daggle.animory.domain.shortform.exception.NotLikedPetVideo;
import com.daggle.animory.domain.shortform.exception.ShortFormNotFound;
import com.daggle.animory.domain.shortform.repository.PetVideoLikeRepository;
import com.daggle.animory.domain.shortform.repository.PetVideoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
public class PetVideoLikeService {
final PetVideoRepository petVideoRepository;
final PetVideoLikeRepository petVideoLikeRepository;

public void updatePetVideoLikeCount(final String IPAddress, final int petVideoId) {
validatePetVideoLikeDuplication(IPAddress, petVideoId);

final PetVideo petVideo = petVideoRepository.findById(petVideoId)
.orElseThrow(ShortFormNotFound::new);

petVideo.updateLikeCount();

petVideoLikeRepository.save(PetVideoLike.builder()
.ipAddress(IPAddress)
.petVideo(petVideo)
.build());
}

public void deletePetVideoLikeCount(final String IPAddress, final int petVideoId) {
validatePetVideoLikeDelete(IPAddress, petVideoId);

final PetVideo petVideo = petVideoRepository.findById(petVideoId)
.orElseThrow(ShortFormNotFound::new);

petVideo.deleteLikeCount();

petVideoLikeRepository.deleteByIpAddressAndPetVideoId(IPAddress, petVideoId);
}

private void validatePetVideoLikeDuplication(final String IPAddress, final int petVideoId) {
if (petVideoLikeRepository.existsByIpAddressAndPetVideoId(IPAddress, petVideoId)) {
throw new AlreadyLikedPetVideo();
}
}

private void validatePetVideoLikeDelete(final String IPAddress, final int petVideoId) {
if (!petVideoLikeRepository.existsByIpAddressAndPetVideoId(IPAddress, petVideoId)) {
throw new NotLikedPetVideo();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.daggle.animory.domain.shortform;
package com.daggle.animory.domain.shortform.service;

import com.daggle.animory.domain.pet.entity.PetVideo;
import com.daggle.animory.domain.shortform.dto.request.ShortFormSearchCondition;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CREATE TABLE pet_video_like
(
id INT NOT NULL,
created_at datetime NULL,
updated_at datetime NULL,
ip_address VARCHAR(255) NOT NULL,
pet_video_id INT NULL,
CONSTRAINT pk_pet_video_like PRIMARY KEY (id)
);

ALTER TABLE pet_video_like
ADD CONSTRAINT FK_PET_VIDEO_LIKE_ON_PET_VIDEO FOREIGN KEY (pet_video_id) REFERENCES pet_video (id);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.daggle.animory.domain.pet.entity.PetType;
import com.daggle.animory.domain.shelter.entity.Province;
import com.daggle.animory.domain.shortform.controller.ShortFormController;
import com.daggle.animory.domain.shortform.service.PetVideoLikeService;
import com.daggle.animory.domain.shortform.service.ShortFormService;
import com.daggle.animory.testutil.webmvctest.BaseWebMvcTest;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand All @@ -25,6 +27,8 @@ class ShortFormControllerTest extends BaseWebMvcTest {
@MockBean
private ShortFormService shortFormService;

@MockBean
private PetVideoLikeService petVideoLikeService;

@Nested
class 카테고리_숏폼_검색 {
Expand Down

0 comments on commit a8a49d7

Please sign in to comment.