mirror of https://github.com/usbharu/Hideout.git
feat: 投稿フォームを追加
This commit is contained in:
parent
1fc6a1fa38
commit
91573c0b2e
|
@ -1,7 +1,6 @@
|
|||
package dev.usbharu.hideout.core.application.post
|
||||
|
||||
import dev.usbharu.hideout.core.application.exception.InternalServerException
|
||||
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
|
||||
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
|
||||
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
|
@ -32,7 +31,7 @@ class GetPostDetailApplicationService(
|
|||
val post = postRepository.findById(PostId(command.postId))
|
||||
?: throw IllegalArgumentException("Post ${command.postId} not found.")
|
||||
if (iPostReadAccessControl.isAllow(post, principal).not()) {
|
||||
throw PermissionDeniedException()
|
||||
throw IllegalArgumentException("Post ${command.postId} not found.")
|
||||
}
|
||||
val actor =
|
||||
actorRepository.findById(post.actorId) ?: throw InternalServerException("Actor ${post.actorId} not found.")
|
||||
|
@ -65,7 +64,7 @@ class GetPostDetailApplicationService(
|
|||
val post = postRepository.findById(postId) ?: return null
|
||||
|
||||
if (iPostReadAccessControl.isAllow(post, principal).not()) {
|
||||
throw PermissionDeniedException()
|
||||
return null
|
||||
}
|
||||
|
||||
val (first, second: Instance, third) = if (actor.id != post.actorId) {
|
||||
|
|
|
@ -83,6 +83,8 @@ class SecurityConfig {
|
|||
authorize(POST, "/auth/sign_up", permitAll)
|
||||
authorize(GET, "/users/{username}/posts/{postId}", permitAll)
|
||||
authorize(GET, "/files/*", permitAll)
|
||||
authorize(POST, "/publish", authenticated)
|
||||
authorize(GET, "/publish", authenticated)
|
||||
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,12 @@ interface IPostReadAccessControl {
|
|||
class DefaultPostReadAccessControl(private val relationshipRepository: RelationshipRepository) :
|
||||
IPostReadAccessControl {
|
||||
override suspend fun isAllow(post: Post, principal: Principal): Boolean {
|
||||
|
||||
//ポスト主は無条件で見れる
|
||||
if (post.actorId == principal.actorId) {
|
||||
return true
|
||||
}
|
||||
|
||||
val relationship = (relationshipRepository.findByActorIdAndTargetId(post.actorId, principal.actorId)
|
||||
?: Relationship.default(post.actorId, principal.actorId))
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package dev.usbharu.hideout.core.interfaces.web.posts
|
||||
|
||||
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
|
||||
import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService
|
||||
import dev.usbharu.hideout.core.application.post.GetPostDetail
|
||||
import dev.usbharu.hideout.core.application.post.GetPostDetailApplicationService
|
||||
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.ui.Model
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
|
@ -18,10 +20,15 @@ class PostsController(
|
|||
@GetMapping("/users/{name}/posts/{id}")
|
||||
suspend fun postById(@PathVariable id: Long, model: Model): String {
|
||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||
try {
|
||||
val post = getPostDetailApplicationService.execute(GetPostDetail(id), principal)
|
||||
val instance = getLocalInstanceApplicationService.execute(Unit, principal)
|
||||
model.addAttribute("post", post)
|
||||
model.addAttribute("instance", instance)
|
||||
} catch (e: PermissionDeniedException) {
|
||||
throw AccessDeniedException("403 Forbidden", e)
|
||||
}
|
||||
|
||||
return "postById"
|
||||
}
|
||||
}
|
|
@ -3,17 +3,23 @@ package dev.usbharu.hideout.core.interfaces.web.posts
|
|||
import dev.usbharu.hideout.core.application.actor.GetUserDetail
|
||||
import dev.usbharu.hideout.core.application.actor.GetUserDetailApplicationService
|
||||
import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService
|
||||
import dev.usbharu.hideout.core.application.post.RegisterLocalPost
|
||||
import dev.usbharu.hideout.core.application.post.RegisterLocalPostApplicationService
|
||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.ui.Model
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.ModelAttribute
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
|
||||
@Controller
|
||||
class PublishController(
|
||||
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService,
|
||||
private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder,
|
||||
private val getUserDetailApplicationService: GetUserDetailApplicationService
|
||||
private val getUserDetailApplicationService: GetUserDetailApplicationService,
|
||||
private val userRegisterLocalPostApplicationService: RegisterLocalPostApplicationService
|
||||
) {
|
||||
@GetMapping("/publish")
|
||||
suspend fun publish(model: Model): String {
|
||||
|
@ -26,7 +32,29 @@ class PublishController(
|
|||
val instance = getLocalInstanceApplicationService.execute(Unit, principal)
|
||||
val userDetail = getUserDetailApplicationService.execute(GetUserDetail(principal.userDetailId!!.id), principal)
|
||||
model.addAttribute("instance", instance)
|
||||
model.addAttribute("user")
|
||||
model.addAttribute("user", userDetail)
|
||||
model.addAttribute("form", PublishPost())
|
||||
return "post-postForm"
|
||||
}
|
||||
|
||||
@PostMapping("/publish")
|
||||
suspend fun publishForm(@ModelAttribute publishPost: PublishPost): String {
|
||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||
if (principal.userDetailId == null) {
|
||||
throw AccessDeniedException("403 Forbidden")
|
||||
}
|
||||
|
||||
val command = RegisterLocalPost(
|
||||
content = publishPost.status.orEmpty(),
|
||||
overview = publishPost.overview,
|
||||
visibility = Visibility.valueOf(publishPost.visibility.uppercase()),
|
||||
repostId = null,
|
||||
replyId = null,
|
||||
sensitive = false,
|
||||
mediaIds = emptyList()
|
||||
)
|
||||
val id = userRegisterLocalPostApplicationService.execute(command, principal)
|
||||
|
||||
return "redirect:/users/${principal.acct?.userpart}/posts/${id}"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package dev.usbharu.hideout.core.interfaces.web.posts
|
||||
|
||||
data class PublishPost(var status: String? = null, var overview: String? = null, var visibility: String = "PUBLIC")
|
|
@ -5,7 +5,15 @@ common.thumbnail=\u30B5\u30E0\u30CD\u30A4\u30EB
|
|||
common.unknwon-file-type=\u4E0D\u660E\u306A\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F
|
||||
common.video=\u52D5\u753B
|
||||
common.video-download-link=\u52D5\u753B\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F\u30B5\u30E0\u30CD\u30A4\u30EB\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9
|
||||
common.visibility=\u516C\u958B\u7BC4\u56F2
|
||||
common.visibility-followers=\u30D5\u30A9\u30ED\u30EF\u30FC\u306E\u307F
|
||||
common.visibility-public=\u30D1\u30D6\u30EA\u30C3\u30AF
|
||||
common.visibility-unlisted=\u672A\u53CE\u8F09
|
||||
post-by-id.title={0} \u3055\u3093\u306E\u6295\u7A3F - {1}
|
||||
post-form.new-posts=\u65B0\u3057\u3044\u6295\u7A3F!
|
||||
post-form.new-posts-cw=CW
|
||||
post-form.new-posts-cw-title=\u30B3\u30F3\u30C6\u30F3\u30C4\u306B\u95B2\u89A7\u6CE8\u610F\u3092\u3064\u3051\u308B
|
||||
post-form.new-posts-form-label=\u4ECA\u306A\u306B\u3057\u3066\u308B?
|
||||
post-form.new-posts-submit=\u6295\u7A3F\u3059\u308B
|
||||
post.repost=\u30EA\u30DD\u30B9\u30C8
|
||||
post.repost-by={0}\u304C\u30EA\u30DD\u30B9\u30C8
|
|
@ -5,6 +5,14 @@ common.thumbnail=thumbnail
|
|||
common.unknwon-file-type=Unknown filetype
|
||||
common.video=Video
|
||||
common.video-download-link=Download the Video or thumbnail.
|
||||
common.visibility=Visibility
|
||||
common.visibility-followers=Followers only
|
||||
common.visibility-public=Public
|
||||
common.visibility-unlisted=Unlisted
|
||||
post-form.new-posts=New Posts!
|
||||
post-form.new-posts-cw=CW
|
||||
post-form.new-posts-cw-title=Add content warning
|
||||
post-form.new-posts-form-label=What's on your mind?
|
||||
post-form.new-posts-submit=Submit!
|
||||
post.repost=Repost
|
||||
post.repost-by=Repost by {0}
|
|
@ -5,7 +5,15 @@ common.thumbnail=\u30B5\u30E0\u30CD\u30A4\u30EB
|
|||
common.unknwon-file-type=\u4E0D\u660E\u306A\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F
|
||||
common.video=\u52D5\u753B
|
||||
common.video-download-link=\u52D5\u753B\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F\u30B5\u30E0\u30CD\u30A4\u30EB\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9
|
||||
common.visibility=\u516C\u958B\u7BC4\u56F2
|
||||
common.visibility-followers=\u30D5\u30A9\u30ED\u30EF\u30FC\u306E\u307F
|
||||
common.visibility-public=\u30D1\u30D6\u30EA\u30C3\u30AF
|
||||
common.visibility-unlisted=\u672A\u53CE\u8F09
|
||||
post-by-id.title={0} \u3055\u3093\u306E\u6295\u7A3F - {1}
|
||||
post-form.new-posts=\u65B0\u3057\u3044\u6295\u7A3F!
|
||||
post-form.new-posts-cw=CW
|
||||
post-form.new-posts-cw-title=\u30B3\u30F3\u30C6\u30F3\u30C4\u306B\u95B2\u89A7\u6CE8\u610F\u3092\u3064\u3051\u308B
|
||||
post-form.new-posts-form-label=\u4ECA\u306A\u306B\u3057\u3066\u308B?
|
||||
post-form.new-posts-submit=\u6295\u7A3F\u3059\u308B
|
||||
post.repost=\u30EA\u30DD\u30B9\u30C8
|
||||
post.repost-by={0}\u304C\u30EA\u30DD\u30B9\u30C8
|
|
@ -1,10 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="single-simple-actor(actor)"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -8,5 +8,44 @@
|
|||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
<div>
|
||||
<img alt="" height="80px" src="" th:src="${user.iconUrl}" width="80px">
|
||||
<div style="display: inline-block">
|
||||
<p th:text="${user.screenName}+'('+${user.name}+'@'+${user.domain}+')'"></p>
|
||||
</div>
|
||||
</div>
|
||||
<form action="/publish" method="post" th:action="@{/publish}" th:object="${form}">
|
||||
<div>
|
||||
<label for="stats-form-overview" th:text="#{post-form.new-posts-cw}"
|
||||
th:title="#{post-form.new-posts-cw-title}"
|
||||
title="Add content warning">CW</label>
|
||||
<input id="stats-form-overview" name="overview" type="text">
|
||||
</div>
|
||||
<div>
|
||||
<label for="status-form" th:text="#{post-form.new-posts-form-label}">What's on your mind?</label>
|
||||
<br>
|
||||
<textarea cols="33" id="status-form" name="status" rows="5"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<fieldset>
|
||||
<legend th:text="#{common.visibility}">Visibility</legend>
|
||||
<label for="status-form-visibility-public" th:text="#{common.visibility-public}">Public</label>
|
||||
<input id="status-form-visibility-public" name="visibility" th:checked="${form.visibility == 'PUBLIC'}" type="radio"
|
||||
value="PUBLIC">
|
||||
<label for="status-form-visibility-unlisted" th:text="#{common.visibility-unlisted}">Unlisted</label>
|
||||
<input id="status-form-visibility-unlisted" name="visibility" th:checked="${form.visibility == 'UNLISTED'}" type="radio"
|
||||
value="UNLISTED">
|
||||
<label for="status-form-visibility-followers" th:text="#{common.visibility-followers}">Followers</label>
|
||||
<input id="status-form-visibility-followers" name="visibility" th:checked="${form.visibility == 'FOLLOWERS'}" type="radio"
|
||||
value="FOLLOWERS">
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<input th:value="#{post-form.new-posts-submit}" type="submit" value="Publish!">
|
||||
</div>
|
||||
</form>
|
||||
</noscript>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue