Skip to content

Commit

Permalink
๐Ÿ”€ Merge pull request #27 from juwon-code/main
Browse files Browse the repository at this point in the history
[Feat] ํ”ผ๋“œ ์ปดํฌ๋„ŒํŠธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐ ๋ฆฌํŒฉํ† ๋ง ์™„๋ฃŒ
  • Loading branch information
juwon-code authored Nov 4, 2024
2 parents 6c32199 + ae2a1d6 commit 9bc878a
Show file tree
Hide file tree
Showing 32 changed files with 475 additions and 385 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.tenten.bittakotlin.chat.controller

import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.http.ResponseEntity
import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.simp.SimpMessagingTemplate
Expand All @@ -9,6 +11,7 @@ import org.springframework.web.bind.annotation.PathVariable
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.RequestParam
import org.springframework.web.bind.annotation.RestController
import org.tenten.bittakotlin.chat.dto.ChatRequestDto
import org.tenten.bittakotlin.chat.dto.ChatResponseDto
Expand All @@ -28,17 +31,20 @@ class ChatController(
private val chatRoomService: ChatRoomService
) {
@MessageMapping("/send")
fun send(@RequestBody requestDto: ChatRequestDto.Send): Unit {
fun send(requestDto: ChatRequestDto.Send): Unit {
val responseDto: ChatResponseDto.Send = chatService.save(requestDto)

simpMessagingTemplate.convertAndSend("/room/${responseDto.chatRoomId}", responseDto)
}

@GetMapping("/room")
fun read(@RequestBody requestDto: ChatRequestDto.Read): ResponseEntity<Map<String, Any>> {
fun read(@RequestParam(defaultValue = "0") page: Int, @RequestParam(defaultValue = "20") size: Int
, @RequestBody requestDto: ChatRequestDto.Read): ResponseEntity<Map<String, Any>> {
val pageable: Pageable = PageRequest.of(page, size)

return ResponseEntity.ok(mapOf(
"message" to "ํŒŒ์ผ ์กฐํšŒ ๋งํฌ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to chatService.get(requestDto)
"message" to "์ฑ„ํŒ… ๋ชฉ๋ก์„ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to chatService.get(pageable, requestDto)
))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.tenten.bittakotlin.chat.repository

import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Slice
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
Expand All @@ -8,6 +10,6 @@ import org.tenten.bittakotlin.chat.entity.Chat

@Repository
interface ChatRepository : JpaRepository<Chat, Long> {
@Query("SELECT c FROM Chat c WHERE c.chatRoom.id = :chatRoomId")
fun findAllByChatRoomId(@Param("chatRoomId") chatRoomId: Long): List<Chat>
@Query("SELECT c FROM Chat c WHERE c.chatRoom.id = :chatRoomId ORDER BY c.id DESC")
fun findAllByChatRoomIdOrderByIdDesc(@Param("chatRoomId") chatRoomId: Long, pageable: Pageable): Slice<Chat>
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.tenten.bittakotlin.chat.service

import org.springframework.data.domain.Pageable
import org.tenten.bittakotlin.chat.dto.ChatRequestDto
import org.tenten.bittakotlin.chat.dto.ChatResponseDto

interface ChatService {
fun get(requestDto: ChatRequestDto.Read): List<ChatResponseDto.Read>
fun get(pageable: Pageable, requestDto: ChatRequestDto.Read): List<ChatResponseDto.Read>

fun save(requestDto: ChatRequestDto.Send): ChatResponseDto.Send

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.tenten.bittakotlin.chat.service

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Slice
import org.springframework.stereotype.Service
import org.tenten.bittakotlin.chat.constant.ChatError
import org.tenten.bittakotlin.chat.dto.ChatRequestDto
Expand All @@ -25,20 +27,20 @@ class ChatServiceImpl(
private val logger: Logger = LoggerFactory.getLogger(ChatServiceImpl::class.java)
}

override fun get(requestDto: ChatRequestDto.Read): List<ChatResponseDto.Read> {
override fun get(pageable: Pageable, requestDto: ChatRequestDto.Read): List<ChatResponseDto.Read> {
var result: MutableList<ChatResponseDto.Read> = mutableListOf()

try {
val chatRoom: ChatRoom = chatRoomService.getChatRoomByNicknames(requestDto.sender, requestDto.receiver)
val chats: List<Chat> = chatRepository.findAllByChatRoomId(chatRoom.id!!)
val chats: Slice<Chat> = chatRepository.findAllByChatRoomIdOrderByIdDesc(chatRoom.id!!, pageable)

chats.forEach { c -> result.add(
chats.forEach { chat -> result.add(
ChatResponseDto.Read(
chatId = c.id!!,
sender = c.profile.nickname,
message = c.message,
deleted = c.deleted,
chatAt = c.createdAt!!
chatId = chat.id!!,
sender = chat.profile.nickname,
message = chat.message,
deleted = chat.deleted,
chatAt = chat.createdAt!!
))
}
} catch (e: NoSuchElementException) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.tenten.bittakotlin.feed.constant

enum class FeedError(val code: Int, val message: String) {
NOT_FOUND(404, "ํ”ผ๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."),
CANNOT_FOUND(404, "ํ”ผ๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."),
CANNOT_MODIFY_BAD_AUTHORITY(403, "ํ”ผ๋“œ๋ฅผ ์ˆ˜์ •ํ•  ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค."),
CANNOT_DELETE_BAD_AUTHORITY(403, "ํ”ผ๋“œ๋ฅผ ์‚ญ์ œํ•  ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค."),
}
Original file line number Diff line number Diff line change
@@ -1,108 +1,74 @@
package org.tenten.bittakotlin.feed.controller

import org.tenten.bittakotlin.feed.dto.FeedDTO
import org.tenten.bittakotlin.feed.dto.FeedRequestDto.Modify
import org.tenten.bittakotlin.feed.service.FeedService
import org.tenten.bittakotlin.global.constants.ApiResponses.*
import org.tenten.bittakotlin.global.exception.AuthenticationException
import org.tenten.bittakotlin.global.util.AuthenticationProvider
import org.tenten.bittakotlin.member.entity.Role
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.Parameters
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.validation.Valid
import jakarta.validation.constraints.Min
import lombok.RequiredArgsConstructor
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.util.Map
import org.tenten.bittakotlin.feed.dto.FeedRequestDto
import org.tenten.bittakotlin.security.service.PrincipalProvider

@Tag(name = "ํ”ผ๋“œ API ์ปจํŠธ๋กค๋Ÿฌ", description = "ํ”ผ๋“œ์™€ ๊ด€๋ จ๋œ REST API๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ปจํ‹€๋กค๋Ÿฌ์ž…๋‹ˆ๋‹ค.")
@RestController
@RequestMapping("/api/v1/feed")
@RequiredArgsConstructor
@Validated
class FeedController {
private val feedService: FeedService? = null


class FeedController (
private val feedService: FeedService
) {
@GetMapping
fun getFeeds(
fun readAll(
@RequestParam(required = false, defaultValue = "0", value = "page") page: Int,
@RequestParam(required = false, defaultValue = "10", value = "size") size: Int,
@RequestParam(required = false, value = "username") username: String?,
@RequestParam(required = false, value = "nickname") nickname: String?,
@RequestParam(required = false, value = "title") title: String?
): ResponseEntity<*> {
): ResponseEntity<Map<String, Any>> {
val pageable: Pageable = PageRequest.of(page, size)

return ResponseEntity.ok<T>(
Map.of<K, V>(
"message", "ํ”ผ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result", feedService.readAll(pageable, username, title)
)
)
return ResponseEntity.ok(mapOf(
"message" to "ํ”ผ๋“œ ๋ชฉ๋ก์„ ์„ฑ๊ณต์ ์œผ๋กœ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to feedService.getAll(pageable, nickname, title)
))
}

@GetMapping("/{id}")
fun getFeedById(@PathVariable("id") id: @Min(1) Long?): ResponseEntity<*> {
return ResponseEntity.ok<T>(
Map.of<K, V>("message", "ํ”ผ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค.", "result", feedService.read(id))
)
@GetMapping("/random")
fun readRandom(@RequestParam(required = false, defaultValue = "0", value = "page") size: Int
): ResponseEntity<Map<String, Any>> {
return ResponseEntity.ok(mapOf(
"message" to "ํ”ผ๋“œ ๋ชฉ๋ก์„ ๋ฌด์ž‘์œ„๋กœ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to feedService.getRandom(size)
))
}

@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE])
fun createFeed(
@RequestPart(value = "feed") feedDto: @Valid FeedDTO?,
@RequestPart(value = "files", required = false) files: List<MultipartFile?>?
): ResponseEntity<*> {
feedService.insert(feedDto, files)
@GetMapping("/{id}")
fun read(@PathVariable("id") id: Long): ResponseEntity<Map<String, Any>> {
return ResponseEntity.ok(mapOf(
"message" to "ํ”ผ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to feedService.get(id)
))
}

return ResponseEntity.ok().body(Map.of("message", "ํ”ผ๋“œ๊ฐ€ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค."))
@PostMapping
fun create(requestDto: FeedRequestDto.Create): ResponseEntity<Map<String, Any>> {
return ResponseEntity.ok(mapOf(
"message" to "ํ”ผ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๋“ฑ๋กํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to feedService.save(requestDto)
))
}

@PutMapping(value = ["/{id}"], consumes = [MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE])
@PutMapping
fun modifyFeed(
@PathVariable("id") id: @Min(1) Long?,
@RequestPart("feed") feedDTO: @Valid Modify,
@RequestPart("filesToUpload") filesToUpload: List<MultipartFile?>?,
@RequestPart("filesToDelete") filesToDelete: List<String?>?
): ResponseEntity<*> {
if (!checkPermission(id)) {
throw AuthenticationException.CANNOT_ACCESS.get()
}

feedDTO.setId(id)

feedService.update(feedDTO, filesToUpload, filesToDelete)

return ResponseEntity.ok().body(Map.of("message", "ํ”ผ๋“œ๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค."))
@PathVariable("id") id: Long, @RequestBody requestDto: FeedRequestDto.Modify):
ResponseEntity<Map<String, Any>> {
return ResponseEntity.ok(mapOf(
"message" to "ํ”ผ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.",
"result" to feedService.update(id, requestDto)
))
}

@DeleteMapping("/{id}")
fun deleteFeed(@PathVariable("id") id: @Min(1) Long?): ResponseEntity<*> {
if (!checkPermission(id)) {
throw AuthenticationException.CANNOT_ACCESS.get()
}

fun deleteFeed(@PathVariable id: Long): ResponseEntity<Map<String, Any>> {
feedService.delete(id)

return ResponseEntity.ok().body(Map.of("message", "ํ”ผ๋“œ๊ฐ€ ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."))
}

private fun checkPermission(id: Long?): Boolean {
if (AuthenticationProvider.getRoles() === Role.ROLE_ADMIN) {
return true
}

return feedService.checkAuthority(id, AuthenticationProvider.getUsername())
return ResponseEntity.ok(mapOf(
"message" to "ํ”ผ๋“œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค."
))
}
}
34 changes: 0 additions & 34 deletions src/main/kotlin/org/tenten/bittakotlin/feed/dto/FeedDTO.kt

This file was deleted.

46 changes: 18 additions & 28 deletions src/main/kotlin/org/tenten/bittakotlin/feed/dto/FeedRequestDto.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
package org.tenten.bittakotlin.feed.dto

import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.Min
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
import jakarta.validation.constraints.Size
import lombok.AllArgsConstructor
import lombok.Builder
import lombok.Data
import lombok.NoArgsConstructor
import org.tenten.bittakotlin.media.dto.MediaRequestDto

class FeedRequestDto {
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class Modify {
@Schema(title = "ํ”ผ๋“œ ID (PK)", description = "ํ”ผ๋“œ์˜ ๊ณ ์œ  ID ์ž…๋‹ˆ๋‹ค.", example = "1", minimum = "1")
val id: @Min(value = 1, message = "ID๋Š” 0 ๋˜๋Š” ์Œ์ˆ˜๊ฐ€ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") Long? = null

@Schema(title = "ํ”ผ๋“œ ์ œ๋ชฉ", description = "ํ”ผ๋“œ ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.", example = "Feed Title", minimum = "1", maximum = "50")
val title: @NotBlank(message = "์ œ๋ชฉ์€ ๋น„์šฐ๊ฑฐ๋‚˜, ๊ณต๋ฐฑ์ด ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") @Size(
min = 1,
max = 50,
message = "์ œ๋ชฉ์€ 1 ~ 50์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."
) String? = null

@Schema(title = "ํ”ผ๋“œ ๋‚ด์šฉ", description = "ํ”ผ๋“œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.", example = "Feed Content")
@Builder.Default
val content: @NotNull String = ""
}
data class Create (
val title: String,

val content: String,

val medias: List<MediaRequestDto.Upload>?
)

data class Modify (
val title: String,

val content: String,

val uploads: List<MediaRequestDto.Upload>?,

val deletes: List<MediaRequestDto.Delete>?
)
}
28 changes: 28 additions & 0 deletions src/main/kotlin/org/tenten/bittakotlin/feed/dto/FeedResponseDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.tenten.bittakotlin.feed.dto

import org.tenten.bittakotlin.media.dto.MediaResponseDto
import java.time.LocalDateTime

class FeedResponseDto {
data class Read (
val id: Long,

val title: String,

val content: String,

val author: String,

val createdAt: LocalDateTime,

val medias: List<MediaResponseDto.Read>
)

data class Create (
val medias: List<MediaResponseDto.Read>
)

data class Modify (
val medias: List<MediaResponseDto.Read>
)
}
Loading

0 comments on commit 9bc878a

Please sign in to comment.