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

Feat/back reaction api #74

Merged
merged 2 commits into from
Nov 25, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.goliath.emojihub.springboot.domain.emoji.service
import com.goliath.emojihub.springboot.global.exception.CustomHttp404
import com.goliath.emojihub.springboot.domain.emoji.dao.EmojiDao
import com.goliath.emojihub.springboot.domain.emoji.dto.EmojiDto
import com.goliath.emojihub.springboot.domain.post.dao.PostDao
import com.goliath.emojihub.springboot.domain.reaction.dao.ReactionDao
import com.goliath.emojihub.springboot.domain.user.dao.UserDao
import com.goliath.emojihub.springboot.global.exception.CustomHttp400
import com.goliath.emojihub.springboot.global.exception.CustomHttp403
Expand All @@ -14,11 +16,14 @@ import org.springframework.web.multipart.MultipartFile
class EmojiService(
private val emojiDao: EmojiDao,
private val userDao: UserDao,
private val reactionDao: ReactionDao,
private val postDao: PostDao
) {

companion object {
const val CREATED_EMOJIS = "created_emojis"
const val SAVED_EMOJIS = "saved_emojis"
const val EMOJI_ID = "emoji_id"
}

fun getEmojis(sortByDate: Int, index: Int, count: Int): List<EmojiDto> {
Expand Down Expand Up @@ -89,10 +94,22 @@ class EmojiService(
fun deleteEmoji(username: String, emojiId: String) {
val emoji = emojiDao.getEmoji(emojiId) ?: throw CustomHttp404("Emoji doesn't exist.")
if (username != emoji.created_by) throw CustomHttp403("You can't delete this emoji.")
val blobName = username + "_" + emoji.created_at + ".mp4"
emojiDao.deleteFileInStorage(blobName)
// delete file and thumbnail in DB
val fileBlobName = username + "_" + emoji.created_at + ".mp4"
val thumbnailBlobName = username + "_" + emoji.created_at + ".jpeg"
emojiDao.deleteFileInStorage(fileBlobName)
emojiDao.deleteFileInStorage(thumbnailBlobName)
// delete all reactions(and reaction id in posts) using this emoji
val reactions = reactionDao.getReactionsWithField(emojiId, EMOJI_ID)
for (reaction in reactions) {
postDao.deleteReactionId(reaction.post_id, reaction.id)
reactionDao.deleteReaction(reaction.id)
}
// delete all saved_emoji ids in users
userDao.deleteAllSavedEmojiId(emojiId)
// delete created_emoji id in user
userDao.deleteId(username, emojiId, CREATED_EMOJIS)
// delete emoji
emojiDao.deleteEmoji(emojiId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import org.springframework.stereotype.Repository
class PostDao(
private val db: Firestore
) {

companion object {
const val POST_COLLECTION_NAME = "Posts"
const val CONTENT = "content"
const val CREATED_AT = "created_at"
const val MODIFIED_AT = "modified_at"
const val REACTIONS = "reactions"
}

fun insertPost(username: String, content: String): PostDto {
Expand All @@ -28,7 +31,7 @@ class PostDao(
fun getPosts(index: Int, count: Int): List<PostDto> {
val list = mutableListOf<PostDto>()
// 정렬
val postQuery = db.collection(POST_COLLECTION_NAME).orderBy("created_at", Query.Direction.DESCENDING)
val postQuery = db.collection(POST_COLLECTION_NAME).orderBy(CREATED_AT, Query.Direction.DESCENDING)
// 페이지네이션
val documents: List<QueryDocumentSnapshot> = postQuery.offset((index - 1) * count).limit(count).get().get().documents
for (document in documents) {
Expand Down Expand Up @@ -64,12 +67,21 @@ class PostDao(
fun updatePost(postId: String, content: String) {
val dateTime = getDateTimeNow()
val postRef = db.collection(POST_COLLECTION_NAME).document(postId)
postRef.update("content", content)
postRef.update("modified_at", dateTime)
postRef.update(CONTENT, content)
postRef.update(MODIFIED_AT, dateTime)
}

fun deletePost(postId: String) {
db.collection(POST_COLLECTION_NAME).document(postId).delete()
}

fun insertReactionId(postId: String, reactionId: String) {
val postRef = db.collection(POST_COLLECTION_NAME).document(postId)
postRef.update(REACTIONS, FieldValue.arrayUnion(reactionId))
}

fun deleteReactionId(postId: String, reactionId: String) {
val postRef = db.collection(POST_COLLECTION_NAME).document(postId)
postRef.update(REACTIONS, FieldValue.arrayRemove(reactionId))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ data class PostDto(
var content: String = "",
var created_at: String = "",
var modified_at: String = "",
var reactions: MutableList<String>? = mutableListOf()
) {
constructor(username: String, content: String, dateTime: String) : this() {
val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.goliath.emojihub.springboot.domain.post.service

import com.goliath.emojihub.springboot.domain.post.dao.PostDao
import com.goliath.emojihub.springboot.domain.post.dto.PostDto
import com.goliath.emojihub.springboot.domain.reaction.dao.ReactionDao
import com.goliath.emojihub.springboot.domain.user.dao.UserDao
import com.goliath.emojihub.springboot.global.exception.CustomHttp400
import com.goliath.emojihub.springboot.global.exception.CustomHttp403
Expand All @@ -11,7 +12,8 @@ import org.springframework.stereotype.Service
@Service
class PostService(
private val postDao: PostDao,
private val userDao: UserDao
private val userDao: UserDao,
private val reactionDao: ReactionDao
) {

companion object {
Expand Down Expand Up @@ -52,7 +54,18 @@ class PostService(
val post = postDao.getPost(postId) ?: throw CustomHttp404("Post doesn't exist.")
if (username != post.created_by)
throw CustomHttp403("You can't delete this post.")
// delete post(and post's reactions)
val reactionIds = post.reactions
if (reactionIds != null) {
for (reactionId in reactionIds) {
val reaction = reactionDao.getReaction(reactionId) ?: continue
if (postId != reaction.post_id) continue
reactionDao.deleteReaction(reactionId)
}
}
// delete created_post id in user
userDao.deleteId(username, postId, CREATED_POSTS)
// delete post
postDao.deletePost(postId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.goliath.emojihub.springboot.domain.reaction.controller

import com.goliath.emojihub.springboot.domain.reaction.dto.ReactionDto
import com.goliath.emojihub.springboot.domain.reaction.service.ReactionService
import com.goliath.emojihub.springboot.domain.user.model.CurrentUser
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/reaction")
class ReactionController(private val reactionService: ReactionService) {

@GetMapping
fun getReactionsOfPost(
@RequestParam(value = "postId", defaultValue = "") postId: String,
): ResponseEntity<List<ReactionDto>> {
return ResponseEntity.ok(reactionService.getReactionsOfPost(postId))
}

@PostMapping
fun postReaction(
@CurrentUser username: String,
@RequestParam(value = "postId", defaultValue = "") postId: String,
@RequestParam(value = "emojiId", defaultValue = "") emojiId: String

): ResponseEntity<Unit> {
return ResponseEntity(
reactionService.postReaction(username, postId, emojiId), HttpStatus.CREATED
)
}

@DeleteMapping
fun deleteReaction(
@CurrentUser username: String,
@RequestParam(value = "reactionId", defaultValue = "") reactionId: String,
): ResponseEntity<Unit> {
return ResponseEntity.ok(reactionService.deleteReaction(username, reactionId))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.goliath.emojihub.springboot.domain.reaction.dao

import com.goliath.emojihub.springboot.domain.reaction.dto.ReactionDto
import com.goliath.emojihub.springboot.global.util.getDateTimeNow
import com.google.cloud.firestore.DocumentSnapshot
import com.google.cloud.firestore.Firestore
import com.google.cloud.firestore.Query
import lombok.extern.slf4j.Slf4j
import org.springframework.stereotype.Repository

@Repository
@Slf4j
class ReactionDao(
private val db: Firestore
) {
companion object {
const val REACTION_COLLECTION_NAME = "Reactions"
const val CREATED_BY = "created_by"
const val POST_ID = "post_id"
const val EMOJI_ID = "emoji_id"
const val CREATED_AT = "created_at"
}

fun insertReaction(username: String, postId: String, emojiId: String): ReactionDto {
val dateTime = getDateTimeNow()
val reaction = ReactionDto(username, postId, emojiId, dateTime)
db.collection(REACTION_COLLECTION_NAME)
.document(reaction.id)
.set(reaction)
return reaction
}

fun existReaction(reactionId: String): Boolean {
val future = db.collection(REACTION_COLLECTION_NAME).document(reactionId).get()
val document: DocumentSnapshot = future.get()
return document.exists()
}

fun existSameReaction(username: String, postId: String, emojiId: String): Boolean {
val reactions = db.collection(REACTION_COLLECTION_NAME)
.whereEqualTo(CREATED_BY, username)
.whereEqualTo(POST_ID, postId)
.whereEqualTo(EMOJI_ID, emojiId)
.get().get().documents
return (reactions.size != 0)
}

fun getReaction(reactionId: String): ReactionDto? {
val future = db.collection(REACTION_COLLECTION_NAME).document(reactionId).get()
val document: DocumentSnapshot = future.get()
return document.toObject(ReactionDto::class.java)
}

fun getReactionsWithField(value: String, field: String): List<ReactionDto> {
val list = mutableListOf<ReactionDto>()
val reactionRef = db.collection(REACTION_COLLECTION_NAME)
val reactionQuery = reactionRef.whereEqualTo(field, value)
.orderBy(CREATED_AT, Query.Direction.DESCENDING)
val documents = reactionQuery.get().get().documents
for (document in documents) {
list.add(document.toObject(ReactionDto::class.java))
}
return list
}

fun deleteReaction(reactionId: String) {
db.collection(REACTION_COLLECTION_NAME).document(reactionId).delete()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.goliath.emojihub.springboot.domain.reaction.dto

import kotlin.streams.asSequence

data class ReactionDto(
var id: String = "",
var created_by: String = "",
var post_id: String = "",
var emoji_id: String = "",
var created_at: String = ""
) {
constructor(username: String, post_id: String, emoji_id: String, dateTime: String) : this() {
val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
val outputStrLength: Long = 20
id = java.util.Random().ints(outputStrLength, 0, source.length)
.asSequence()
.map(source::get)
.joinToString("")
created_by = username
this.post_id = post_id
this.emoji_id = emoji_id
created_at = dateTime
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.goliath.emojihub.springboot.domain.reaction.service

import com.goliath.emojihub.springboot.domain.emoji.dao.EmojiDao
import com.goliath.emojihub.springboot.domain.post.dao.PostDao
import com.goliath.emojihub.springboot.domain.reaction.dao.ReactionDao
import com.goliath.emojihub.springboot.domain.reaction.dto.ReactionDto
import com.goliath.emojihub.springboot.domain.user.dao.UserDao
import com.goliath.emojihub.springboot.global.exception.CustomHttp403
import com.goliath.emojihub.springboot.global.exception.CustomHttp404
import org.springframework.stereotype.Service

@Service
class ReactionService(
private val reactionDao: ReactionDao,
private val userDao: UserDao,
private val postDao: PostDao,
private val emojiDao: EmojiDao
) {
companion object {
const val POST_ID = "post_id"
}


fun getReactionsOfPost(postId: String): List<ReactionDto> {
if (!postDao.existPost(postId)) throw CustomHttp404("Post doesn't exist.")
return reactionDao.getReactionsWithField(postId, POST_ID)
}

fun postReaction(username: String, postId: String, emojiId: String) {
if (!userDao.existUser(username)) throw CustomHttp404("User doesn't exist.")
if (!postDao.existPost(postId)) throw CustomHttp404("Post doesn't exist.")
if (!emojiDao.existsEmoji(emojiId)) throw CustomHttp404("Emoji doesn't exist.")
if (reactionDao.existSameReaction(username, postId, emojiId)) throw CustomHttp403("User already react to this post with this emoji.")
val reaction = reactionDao.insertReaction(username, postId, emojiId)
postDao.insertReactionId(postId, reaction.id)
}

fun deleteReaction(username: String, reactionId: String) {
val reaction = reactionDao.getReaction(reactionId) ?: throw CustomHttp404("Reaction doesn't exist.")
if (username != reaction.created_by)
throw CustomHttp403("You can't delete this reaction.")
// delete reaction id in post
postDao.deleteReactionId(reaction.post_id, reactionId)
// delete reaction
reactionDao.deleteReaction(reactionId)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.goliath.emojihub.springboot.domain.user.dao

import com.goliath.emojihub.springboot.domain.emoji.dao.EmojiDao
import com.goliath.emojihub.springboot.domain.user.dto.UserDto
import com.google.cloud.firestore.DocumentSnapshot
import com.google.cloud.firestore.FieldValue
Expand Down Expand Up @@ -66,7 +65,7 @@ class UserDao(
}

fun deleteAllSavedEmojiId(emojiId: String) {
val usersWithDeletedEmoji = db.collection(EmojiDao.USER_COLLECTION_NAME)
val usersWithDeletedEmoji = db.collection(USER_COLLECTION_NAME)
.whereArrayContains("saved_emojis", emojiId)
.get().get().documents
for (user in usersWithDeletedEmoji) {
Expand Down
Loading