Skip to content
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 @@ -59,13 +59,14 @@ class GithubApiService(
githubUsername: String,
repo: String,
path: String,
commitMessage: String = "Upsert File by API",
commitMessage: String,
sha: String = "",
): GithubContent {
val request =
GithubUpsertFileRequest(
message = "Add New File",
message = commitMessage,
content = Base64Encoder.encodeBase64(content),
sha = "",
sha = sha,
)
val response =
githubResourceApiClient.upsertFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,11 @@ interface IPostingController {
githubUsername: String,
postingId: Long,
): ResponseEntity<ApiResponseBody<PostingReadDto>>

fun updatePosting(
id: Long,
title: String,
content: MultipartFile,
member: Member,
): ResponseEntity<ApiResponseBody<PostingReadDto>>
}
15 changes: 15 additions & 0 deletions src/main/kotlin/com/ixfp/gitmon/controller/PostingController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestAttribute
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
Expand All @@ -37,6 +38,20 @@ class PostingController(
return ApiResponseHelper.created(posting)
}

@PutMapping(
consumes = [MediaType.MULTIPART_FORM_DATA_VALUE],
)
override fun updatePosting(
@RequestParam id: Long,
@RequestParam title: String,
@RequestPart content: MultipartFile,
@RequestAttribute(AUTHENTICATED_MEMBER) member: Member,
): ResponseEntity<ApiResponseBody<PostingReadDto>> {
val updatedPosting = postingService.update(member, id, title, content)
val posting = postingService.findPosting(updatedPosting)
return ApiResponseHelper.success(posting)
}

@GetMapping("/{exposedMemberId}")
override fun getPostingList(
@PathVariable exposedMemberId: String,
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/com/ixfp/gitmon/db/posting/PostingEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class PostingEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val title: String,
var title: String,
val refMemberId: Long,
val githubFilePath: String,
val githubFileSha: String,
val githubDownloadUrl: String,
var githubFilePath: String,
var githubFileSha: String,
var githubDownloadUrl: String,
) : BaseEntity()
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.ixfp.gitmon.domain.posting

object CommitMessageGenerator {
fun createMessage(title: String): String {
return "Create \"$title\" - by Gitmon 👾"
}

fun updateMessage(title: String): String {
return "Update \"$title\" - by Gitmon 👾"
}

fun deleteMessage(title: String): String {
return "Delete \"$title\" - by Gitmon 👾"
}

fun imageUploadMessage(): String {
return "Upload image - by Gitmon 👾"
}
}
14 changes: 14 additions & 0 deletions src/main/kotlin/com/ixfp/gitmon/domain/posting/Posting.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ixfp.gitmon.domain.posting

import java.time.LocalDateTime

data class Posting(
val id: Long,
val title: String,
val refMemberId: Long,
val githubFilePath: String,
val githubFileSha: String,
val githubDownloadUrl: String,
val createdAt: LocalDateTime,
val updatedAt: LocalDateTime,
)
15 changes: 9 additions & 6 deletions src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingReader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import org.springframework.stereotype.Component
class PostingReader(
private val postingRepository: PostingRepository,
) {
fun findPostingListByMemberId(memberId: Long): List<PostingReadDto> {
return postingRepository.findByRefMemberId(memberId).map { toPostingItem(it) }
fun findPostingListByMemberId(memberId: Long): List<Posting> {
return postingRepository.findByRefMemberId(memberId).map { toPosting(it) }
}

fun findPostingById(postingId: Long): PostingReadDto {
fun findPostingById(postingId: Long): Posting {
return postingRepository.findById(postingId)
.orElseThrow { IllegalArgumentException("Posting with id $postingId not found") }
.let { toPostingItem(it) }
.let { toPosting(it) }
}

private fun toPostingItem(entity: PostingEntity): PostingReadDto {
return PostingReadDto(
private fun toPosting(entity: PostingEntity): Posting {
return Posting(
id = entity.id,
title = entity.title,
refMemberId = entity.refMemberId,
githubFilePath = entity.githubFilePath,
githubFileSha = entity.githubFileSha,
githubDownloadUrl = entity.githubDownloadUrl,
createdAt = entity.createdAt,
updatedAt = entity.updatedAt,
Expand Down
64 changes: 60 additions & 4 deletions src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.ixfp.gitmon.common.aop.WrapWith
import com.ixfp.gitmon.domain.member.Member
import com.ixfp.gitmon.domain.member.MemberService
import com.ixfp.gitmon.domain.posting.exception.InvalidImageExtensionException
import com.ixfp.gitmon.domain.posting.exception.PostingAuthorizationException
import com.ixfp.gitmon.domain.posting.exception.PostingExceptionStrategy
import com.ixfp.gitmon.domain.posting.exception.PostingRepositoryNotFoundException
import io.github.oshai.kotlinlogging.KotlinLogging.logger
Expand All @@ -23,6 +24,7 @@ class PostingService(
fun findPostingListByMemberExposedId(memberExposedId: String): List<PostingReadDto> {
val member = memberService.getMemberByExposedId(memberExposedId)
return postingReader.findPostingListByMemberId(member.id)
.map { toPostingReadDto(it) }
}

fun findPostingListByGithubUsername(githubUsername: String): List<PostingReadDto> {
Expand All @@ -32,16 +34,16 @@ class PostingService(
val postingList = postingReader.findPostingListByMemberId(member.id)

log.info { "[PostingService] 포스팅 목록 조회 완료. githubUsername=${member.githubUsername}, postingList.size=${postingList.size}" }
return postingList
return postingList.map { toPostingReadDto(it) }
}

fun findPosting(postingId: Long): PostingReadDto? {
fun findPosting(postingId: Long): PostingReadDto {
log.info { "[PostingService] 포스팅 조회 시작. postingId=$postingId" }

val posting = postingReader.findPostingById(postingId)

log.info { "[PostingService] 포스팅 조회 완료. posting=$posting" }
return posting
return toPostingReadDto(posting)
}

fun findPosting(
Expand All @@ -56,7 +58,7 @@ class PostingService(
.find { it.id == postingId }

log.info { "[PostingService] 포스팅 조회 완료. githubUsername=${member.githubUsername}, posting=$posting" }
return posting
return posting?.let { toPostingReadDto(it) }
}

fun create(
Expand All @@ -78,6 +80,7 @@ class PostingService(
githubUsername = member.githubUsername,
repo = member.repoName,
path = "$title.md",
commitMessage = CommitMessageGenerator.createMessage(title = title),
)

val savedPostingId =
Expand All @@ -95,6 +98,48 @@ class PostingService(
return savedPostingId
}

fun update(
member: Member,
postingId: Long,
title: String,
content: MultipartFile,
): Long {
log.info { "PostingService#update start. member=$member, postingId=$postingId, title=$title, content.size=${content.size}" }
val posting = postingReader.findPostingById(postingId)

if (posting.refMemberId != member.id) {
log.warn { "본인이 작성하지 않은 포스팅에 대한 수정 시도. memberId=${member.id}, postingId=$postingId" }
throw PostingAuthorizationException()
}

val githubAccessToken = memberService.getGithubAccessTokenById(member.id)

val githubContent =
githubApiService.upsertFile(
githubAccessToken = githubAccessToken,
content = content,
githubUsername = member.githubUsername,
repo = member.repoName ?: throw PostingRepositoryNotFoundException(),
path = "$title.md",
commitMessage = CommitMessageGenerator.updateMessage(title = title),
sha = posting.githubFileSha,
)

val updatedPostingId =
postingWriter.update(
postingId,
PostingUpdateDto(
title = title,
githubFilePath = githubContent.path,
githubFileSha = githubContent.sha,
githubDownloadUrl = githubContent.download_url,
),
)

log.info { "PostingService#update end. updatedPostingId=$updatedPostingId, contentSha=${githubContent.sha}" }
return updatedPostingId
}

private fun uploadImage(
member: Member,
content: MultipartFile,
Expand All @@ -116,6 +161,7 @@ class PostingService(
githubUsername = member.githubUsername,
repo = member.repoName,
path = path,
commitMessage = CommitMessageGenerator.imageUploadMessage(),
)

return githubContent.download_url
Expand All @@ -136,6 +182,16 @@ class PostingService(
return null
}

private fun toPostingReadDto(posting: Posting): PostingReadDto {
return PostingReadDto(
id = posting.id,
title = posting.title,
githubDownloadUrl = posting.githubDownloadUrl,
createdAt = posting.createdAt,
updatedAt = posting.updatedAt,
)
}

companion object {
private val log = logger {}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.ixfp.gitmon.domain.posting

data class PostingUpdateDto(
val title: String,
val githubFilePath: String,
val githubFileSha: String,
val githubDownloadUrl: String,
)
19 changes: 19 additions & 0 deletions src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingWriter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.ixfp.gitmon.common.aop.WrapWith
import com.ixfp.gitmon.db.exception.DbExceptionStrategy
import com.ixfp.gitmon.db.posting.PostingEntity
import com.ixfp.gitmon.db.posting.PostingRepository
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Component

@WrapWith(DbExceptionStrategy::class)
Expand All @@ -24,4 +25,22 @@ class PostingWriter(

return saved.id
}

fun update(
postingId: Long,
postingUpdateDto: PostingUpdateDto,
): Long {
val postingEntity =
postingRepository.findByIdOrNull(postingId)
?: throw IllegalArgumentException("Posting with id $postingId not found")

postingEntity.title = postingUpdateDto.title
postingEntity.githubFilePath = postingUpdateDto.githubFilePath
postingEntity.githubFileSha = postingUpdateDto.githubFileSha
postingEntity.githubDownloadUrl = postingUpdateDto.githubDownloadUrl

val updated = postingRepository.save(postingEntity)

return updated.id
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ class InvalidImageExtensionException(
cause: Throwable? = null,
) : PostingException(message, cause)

class PostingAuthorizationException(
message: String = "게시글에 대한 권한이 없습니다.",
cause: Throwable? = null,
) : PostingException(message, cause)

class PostingUnexpectedException(
message: String = "예상치 못한 게시글 도메인 예외가 발생했습니다.",
cause: Throwable? = null,
Expand Down