Skip to content

Commit

Permalink
Merge pull request #423 from Team-Ampersand/413-music-like-cancel-fun…
Browse files Browse the repository at this point in the history
…ction

음악 좋아요, 좋아요 삭제 기능
  • Loading branch information
ta2ye0n authored Sep 15, 2024
2 parents 54d7230 + 29e5c10 commit 1865cd2
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 6 deletions.
23 changes: 23 additions & 0 deletions src/main/kotlin/com/dotori/v2/domain/like/entity/Like.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.dotori.v2.domain.like.entity

import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.Table

@Entity
@Table(name = "likes")
class Like (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "like_id")
val id: Long = 0,

@Column(name = "music_id", nullable = false)
val musicId: Long,

@Column(name = "member_id", nullable = false)
val memberId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dotori.v2.domain.like.repository

import com.dotori.v2.domain.member.domain.entity.Member
import com.dotori.v2.domain.like.entity.Like
import com.dotori.v2.domain.music.domain.entity.Music
import feign.Param
import javax.persistence.LockModeType
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Lock
import org.springframework.data.jpa.repository.Query

interface LikeRepository : JpaRepository<Like, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select l from Like l where l.memberId = :memberId and l.musicId = :musicId")
fun findByMemberIdAndMusicId(@Param("memberId") memberId: Long, @Param("musicId") musicId: Long): Like?
}
12 changes: 10 additions & 2 deletions src/main/kotlin/com/dotori/v2/domain/music/domain/entity/Music.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,17 @@ class Music(
val thumbnail: String,

@Column(name = "like_count", nullable = false, columnDefinition = "INT default 0")
val likeCount: Int = 0,
var likeCount: Int = 0,

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
val member: Member
) : BaseTimeEntity()
) : BaseTimeEntity() {
fun plusLikeCount() {
this.likeCount++
}

fun minusLikeCount() {
this.likeCount--
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.dotori.v2.domain.music.exception

import com.dotori.v2.global.error.ErrorCode
import com.dotori.v2.global.error.exception.BasicException

class NotValidMusicLikeException : BasicException(ErrorCode.NOT_VALID_MUSIC_LIKE) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.dotori.v2.domain.music.presentation.admin
import com.dotori.v2.domain.music.presentation.data.res.MusicListResDto
import com.dotori.v2.domain.music.service.DeleteMusicService
import com.dotori.v2.domain.music.service.FindMusicsService
import com.dotori.v2.domain.music.service.ToggleMusicLikeService
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
Expand All @@ -13,7 +14,8 @@ import java.time.LocalDate
@RequestMapping("/v2/admin/music")
class AdminMusicController(
private val findMusicsService: FindMusicsService,
private val deleteMusicService: DeleteMusicService
private val deleteMusicService: DeleteMusicService,
private val toggleMusicLikeService: ToggleMusicLikeService
) {
@GetMapping
fun findMusics(
Expand All @@ -29,4 +31,8 @@ class AdminMusicController(
deleteMusicService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.NO_CONTENT).build() }

@PatchMapping("/{music_id}/like")
fun toggleMusicLike(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
toggleMusicLikeService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.OK).build() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.dotori.v2.domain.music.presentation.data.res.MusicListResDto
import com.dotori.v2.domain.music.service.ApplyMusicService
import com.dotori.v2.domain.music.service.DeleteMusicService
import com.dotori.v2.domain.music.service.FindMusicsService
import com.dotori.v2.domain.music.service.ToggleMusicLikeService
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
Expand All @@ -17,7 +18,8 @@ import java.time.LocalDateTime
class CouncillorMusicController(
private val applyMusicService: ApplyMusicService,
private val findMusicsService: FindMusicsService,
private val deleteMusicService: DeleteMusicService
private val deleteMusicService: DeleteMusicService,
private val toggleMusicLikeService: ToggleMusicLikeService
) {
@PostMapping
fun applyMusic(@RequestBody applyMusicReqDto: ApplyMusicReqDto): ResponseEntity<Void> =
Expand All @@ -37,4 +39,9 @@ class CouncillorMusicController(
fun deleteMusic(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
deleteMusicService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.NO_CONTENT).build() }

@PatchMapping("/{music_id}/like")
fun toggleMusicLike(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
toggleMusicLikeService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.OK).build() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.dotori.v2.domain.music.presentation.data.res.MusicListResDto
import com.dotori.v2.domain.music.service.ApplyMusicService
import com.dotori.v2.domain.music.service.DeleteMusicService
import com.dotori.v2.domain.music.service.FindMusicsService
import com.dotori.v2.domain.music.service.ToggleMusicLikeService
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
Expand All @@ -17,7 +18,8 @@ import java.time.LocalDateTime
class DeveloperMusicController(
private val applyMusicService: ApplyMusicService,
private val findMusicsService: FindMusicsService,
private val deleteMusicService: DeleteMusicService
private val deleteMusicService: DeleteMusicService,
private val toggleMusicLikeService: ToggleMusicLikeService
) {
@PostMapping
fun applyMusic(@RequestBody applyMusicReqDto: ApplyMusicReqDto): ResponseEntity<Void> =
Expand All @@ -37,4 +39,9 @@ class DeveloperMusicController(
fun deleteMusic(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
deleteMusicService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.NO_CONTENT).build() }

@PatchMapping("/{music_id}/like")
fun toggleMusicLike(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
toggleMusicLikeService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.OK).build() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.dotori.v2.domain.music.presentation.data.res.MusicListResDto
import com.dotori.v2.domain.music.service.ApplyMusicService
import com.dotori.v2.domain.music.service.DeleteMyMusicService
import com.dotori.v2.domain.music.service.FindMusicsService
import com.dotori.v2.domain.music.service.ToggleMusicLikeService
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
Expand All @@ -17,7 +18,8 @@ import java.time.LocalDateTime
class MemberMusicController(
private val applyMusicService: ApplyMusicService,
private val findMusicsService: FindMusicsService,
private val deleteMyMusicService: DeleteMyMusicService
private val deleteMyMusicService: DeleteMyMusicService,
private val toggleMusicLikeService: ToggleMusicLikeService
) {
@PostMapping
fun applyMusic(@RequestBody applyMusicReqDto: ApplyMusicReqDto): ResponseEntity<Void> =
Expand All @@ -37,4 +39,9 @@ class MemberMusicController(
fun deleteMusic(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
deleteMyMusicService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.NO_CONTENT).build() }

@PatchMapping("/{music_id}/like")
fun toggleMusicLike(@PathVariable("music_id") musicId: Long): ResponseEntity<Void> =
toggleMusicLikeService.execute(musicId)
.run { ResponseEntity.status(HttpStatus.OK).build() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.dotori.v2.domain.music.service

interface ToggleMusicLikeService {
fun execute(musicId: Long)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.dotori.v2.domain.music.service.impl

import com.dotori.v2.domain.like.entity.Like
import com.dotori.v2.domain.like.repository.LikeRepository
import com.dotori.v2.domain.member.domain.entity.Member
import com.dotori.v2.domain.music.domain.entity.Music
import com.dotori.v2.domain.music.domain.repository.MusicRepository
import com.dotori.v2.domain.music.exception.MusicNotFoundException
import com.dotori.v2.domain.music.service.ToggleMusicLikeService
import com.dotori.v2.global.util.UserUtil
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(readOnly = false, rollbackFor = [Exception::class])
class ToggleMusicLikeServiceImpl(
private val likeRepository: LikeRepository,
private val musicRepository: MusicRepository,
private val userUtil: UserUtil
): ToggleMusicLikeService {
override fun execute(musicId: Long) {
val member = userUtil.fetchCurrentUser()
val music: Music = musicRepository.findByIdOrNull(musicId) ?: throw MusicNotFoundException()

updateLike(music, member)
}

private fun updateLike(music: Music, member: Member) {
val like = likeRepository.findByMemberIdAndMusicId(member.id, music.id)

if (like == null) {
saveLike(music, member)
} else {
deleteLike(like.id, music)
}
}

private fun saveLike(music: Music, member: Member) {
val like = Like (
musicId = music.id,
memberId = member.id
)
likeRepository.save(like)
music.plusLikeCount()
}

private fun deleteLike (likeId: Long, music: Music) {
likeRepository.deleteById(likeId)
music.minusLikeCount()
}

}
1 change: 1 addition & 0 deletions src/main/kotlin/com/dotori/v2/global/error/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum class ErrorCode(
MUSIC_TODAY_NOT_REQUESTED(HttpStatus.ACCEPTED.value(), "오늘 신청된 음악이 없습니다."),
MUSIC_NOT_REQUEST_ON_THAT_DATE(HttpStatus.ACCEPTED.value(), "해당 날짜에 신청된 노래가 없습니다."),
NOT_VALID_YOUTUBE_URL(HttpStatus.BAD_REQUEST.value(), "유효하지 않은 유튜브 url 입니다."),
NOT_VALID_MUSIC_LIKE(HttpStatus.BAD_REQUEST.value(), "이미 지난 요일의 기상음악에는 좋아요를 누를 수 없습니다."),


// *** TOKEN ***
Expand Down

0 comments on commit 1865cd2

Please sign in to comment.